[23C班1B] Glacial Core

发布时间 2023-07-25 20:16:16作者: 灰鲭鲨

题面

平面上有 \(n\) 个点,第 \(i\) 个点的坐标为 \((x_i,y_i)\),权值为 \(w_i\)。编号不同的点可能重合,且 \(w_i\) 可能是负数。

现在你要选择 \(3\) 个整数 \(l,r,k\),并取走所有满足 \(l\le x_i\le r,y_i\le k\) 的点。问对于所有可能的情况,你取走的点的权值和的最大值。

对于所有数据,\(1\le n\le 2.5\times10^5,1\le x_i,y_i,|w_i|≤10^9\)

题解

考虑枚举 \(k\),然后这是我们需要单点修改,求最大子段和。线段树维护即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2.5e5+5;
struct dian{
	int x,y,w;
	bool operator<(const dian&d)const{
		return y<d.y;
	}
}p[N];
int n,lsh[N];
LL s[N],ans;
struct node{
	LL ls,rs,s,ans;
	node operator+(const node&n)const{
		return (node){max(ls,s+n.ls),max(n.rs,n.s+rs),s+n.s,max({ans,n.ans,rs+n.ls})};
	}
}tr[N<<2];
int read()
{
	int s=0,fl=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			fl=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
		s=s*10+ch-48,ch=getchar();
	return s*fl;
}
void upd(int o,int l,int r,int x,LL y)
{
	if(l==r)
	{
		tr[o].s=y;
		tr[o].ls=tr[o].rs=tr[o].ans=max(y,0LL);
		return;
	}
	int md=l+r>>1;
	if(md>=x)
		upd(o<<1,l,md,x,y);
	else
		upd(o<<1|1,md+1,r,x,y);
	tr[o]=tr[o<<1]+tr[o<<1|1];
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)
		p[i].x=read(),p[i].y=read(),p[i].w=read(),lsh[i]=p[i].x;
	sort(lsh+1,lsh+n+1);
	for(int i=1;i<=n;i++)
		p[i].x=lower_bound(lsh+1,lsh+n+1,p[i].x)-lsh;
	sort(p+1,p+n+1);
	for(int l=1;l<=n;)
	{
		int r=l;
		while(r<=n&&p[r].y==p[l].y)
		{
			s[p[r].x]+=p[r].w;
			upd(1,1,n,p[r].x,s[p[r].x]);
			++r;
		}
		l=r;
		ans=max(ans,tr[1].ans);
	}
	printf("%lld",ans);
}