<span>2019牛客暑期多校训练营(第一场)I dp+线段树</span>

题意

给出n个点,每个点有a,b两个属性,让你从左下角到右上角划一条线,线的左边每个点的贡献是\(a_i\),线的右边每个点的贡献是\(b_i\),使得两部分的总和最大。

分析

找一条折线将点分割开,使总和最大。

把y离散化,然后点按x排序,设\(dp[i]\)为经过第\(i\)个点(该点当作B集合中的点)的折线的权值,之前的点中在这个点上面的点dp值要加上\(b[i]\),之前的点中在这个点下面的点的dp值要加上\(a[i]\)

  • \(dp[i]=max(dp[i],dp[k]+b[i]),y[k]<=y[i]\)
  • \(dp[k]=dp[k]+b[i],y[k]>y[i]\)
  • \(dp[k]=dp[k]+a[i],y[k]<y[i]\)

用线段树来维护dp值就行了

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=1e5+10;
int n;
struct ppo{
	int x,y,a,b;
	bool operator <(const ppo &r) const{
		if(x==r.x) return y>r.y;
		return x<r.x;
	}
}a[maxn];
int b[maxn],m;
ll tr[maxn<<2],tag[maxn<<2];
void pp(int p){
	tr[p]=max(tr[p<<1],tr[p<<1|1]);
}
void pd(int p,ll k){
	tr[p]+=k;tag[p]+=k;
}
void bd(int l,int r,int p){
	tag[p]=0;
	if(l==r){
		tr[p]=0;return;
	}int mid=l+r>>1;
	bd(lson);bd(rson);pp(p);
}
void up(int x,int l,int r,int p,ll k){
	if(l==r){
		tr[p]=max(tr[p],k);return;
	}int mid=l+r>>1;
	pd(p<<1,tag[p]);pd(p<<1|1,tag[p]);tag[p]=0;
	if(x<=mid) up(x,lson,k);
	else up(x,rson,k);pp(p);
}
void add(int dl,int dr,int l,int r,int p,ll k){
	if(l>r) return;
	if(l>=dl&&r<=dr){
		tr[p]+=k;tag[p]+=k;return;
	}int mid=l+r>>1;
	pd(p<<1,tag[p]);pd(p<<1|1,tag[p]);tag[p]=0;
	if(dl<=mid) add(dl,dr,lson,k);
	if(dr>mid) add(dl,dr,rson,k);pp(p);
}
ll qy(int dl,int dr,int l,int r,int p){
	if(l>r) return 0;
	if(l>=dl&&r<=dr){
		return tr[p];
	}int mid=l+r>>1;ll ret=0;
	pd(p<<1,tag[p]);pd(p<<1|1,tag[p]);tag[p]=0;
	if(dl<=mid) ret=max(ret,qy(dl,dr,lson));
	if(dr>mid) ret=max(ret,qy(dl,dr,rson));
	return ret;
}
int main(){
	//ios::sync_with_stdio(false);
	//freopen("in","r",stdin);
	while(~scanf("%d",&n)){
		for(int i=1;i<=n;i++){
			scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].a,&a[i].b);
			b[i]=a[i].y;
		}
		sort(b+1,b+n+1);
		m=unique(b+1,b+n+1)-b-1;
		for(int i=1;i<=n;i++){
			a[i].y=lower_bound(b+1,b+m+1,a[i].y)-b+1;
		}
		sort(a+1,a+n+1);
		m++;
		bd(1,m,1);
		for(int i=1;i<=n;i++){
			ll ret=qy(1,a[i].y,1,m,1);
			up(a[i].y,1,m,1,ret+a[i].b);
			add(1,a[i].y-1,1,m,1,a[i].a);
			add(a[i].y+1,m,1,m,1,a[i].b);
		}
		printf("%lld\n",tr[1]);
	}
	return 0;
}
全部评论

相关推荐

A1istair3Zz:你这个hr蛮不错的 开门见山。不像别的 话术算尽
点赞 评论 收藏
分享
伟大的烤冷面被普调:暨大✌🏻就是强
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
昨天 15:43
mamazi00:领导你好+小作文。就算给你涨薪,其实也是待不久了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务