fjnuoj 胖哥的毕业生活

胖哥终于毕业了,他和妹子都租在同一个公寓,由于这个公寓很特别,他和妹子的楼层隔着一个条直线的围栏,因此每次胖哥去看望妹子的时候都需要绕很远的路(至于找妹子做什么,也许是玩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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blaze Jack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值