胖哥终于毕业了,他和妹子都租在同一个公寓,由于这个公寓很特别,他和妹子的楼层隔着一个条直线的围栏,因此每次胖哥去看望妹子的时候都需要绕很远的路(至于找妹子做什么,也许是玩OOXX的游戏,谁知道呢)。


但是机(饥)智(渴)的胖哥想出了一个好办法,他决定将围栏切割成两部分,这样他就能通过围栏去找妹子了。但是胖哥是一个虔诚的佛教教徒,讲究因果,他这样把人家的围栏拆了有违天理,于是他决定将围栏拆的唯美一点。。。。。。


他利用佛教求签的方式给围栏的每块木板定了幸运值,围栏被切割成了两部分但是顺序没变,他会抽掉一些无用的木板,为了让左边围栏和右边围栏的幸运值都能是递增。但是这样还不够,胖哥觉得还不够唯美,他希望右边木板的幸运值总合减去左边木板幸运值的总和是最大的。。。。。。


虽然胖哥想的很美好,但是这个难题机(饥)智(渴)的胖哥也想不出方案,希望你能帮组虔诚的胖哥。



Input


每组数据第一行一个正整数T,表示数据组数 (T <= 20)
接下来T组数据:
第一行是一个正整数n,表示围栏的木板数 ( 1 <= n <= 100000 )
第二行包含n个正整数vi,表示围栏木板的幸运值 ( | i | <= 100000 )


Output


对于每组数据输出一个正整数占一行,表示右边木板幸运值总合减去左边木板幸运值总和的最大值。(请注意,丧心病狂的胖哥既可以拆光左边的围栏也可以拆光右边的围栏,甚至两边的。。。。)


Sample Input

5
10
1 2 3 4 5 6 7 8 9 10
10
10 9 8 7 6 5 4 3 2 1
1
1
10
20 -2 -3 -4 -5 -6 -7 -8 -9 -10
10
233 -1 -2 -3 100 -4 -5 -6 -7 134

Sample Output

55
10
1
54
240

 线段树加上dp的思想,记录一下自己历程。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
#define lson l, mid, rt * 2
#define rson mid + 1, r, rt * 2 + 1
const int mx = (1e5 + 10);
using namespace std;
struct node{
int nu, po;
bool operator < (node A)const{
return nu < A.nu;
}

}data[mx];

ll fr[mx], ba[mx], num[mx], sum[mx * 4];
int n, m, wei[mx];
ll query(int L, int R, int l, int r, int rt){
if(L <= l && r <= R) return sum[rt];
int mid = ( l + r) / 2;
ll ans = 0;
if( L <= mid ) ans = query(L, R, lson);
if(mid < R) ans = max(ans, query(L, R, rson));
return ans;
}
void updata(int po, ll num, int l, int r, int rt){ // ll num 写成 int num
if(l == r){
sum[rt] = num;
return;
}
int mid = (l + r) / 2;
if(po <= mid) updata(po, num, lson);
else updata(po, num, rson);
sum[rt] = max(sum[rt * 2], sum[rt * 2 + 1]);
}
void cmp(int x, ll *p){
if(num[x] <= 0){
p[x] = 0;
}
else{
if(wei[x]== m)
p[x] = num[x];
else{
ll ret = query(wei[x] + 1, m, 1, m, 1);
p[x]= num[x] + ret ;
}
}
updata(wei[x], p[x], 1, m ,1);
}

int main(){
int T;
//freopen("1in","r",stdin);
scanf("%d", &T);
while(T--){
scanf("%d", &n);
memset(sum, 0, sizeof(sum));

for(int i = 1; i <= n; i++){
scanf("%d", &data[i].nu);
num[i] = data[i].nu;
data[i].po = i;
}
sort(data + 1, data + n + 1);

m = wei[data[1].po] = 1;
for(int i = 2; i <= n; i++){
if(data[i].nu != data[i - 1].nu) m++;
wei[data[i].po] = m;
}

for(int i = n; i >= 1; i--)
cmp(i, ba);
ba[n + 1] = 0;
for(int i = n; i >= 1; i--)
ba[i] = max(ba[i], ba[i+1]);

memset(sum, 0, sizeof(sum)); //忘了初始化
for(int i = 1; i <= n; i++){
num[i] = -num[i];
cmp(i, fr);
}
fr[0] = 0;
for(int i = 1; i <= n; i++)
fr[n] = max(fr[n - 1], fr[n]);
ll ans = 0;
for(int i = 0; i <= n ; i++) // 注意边界
ans = max(ans, fr[i] + ba[i+1]);

cout<<ans<<endl;

}
return 0;
}