题解:P12119 [NordicOI 2025] 垃圾收集 / Garbage Collection
思路
我们考虑将垃圾按
这个集合的维护是简单的,从左往右扫,每次遇到一个新的垃圾就去集合末尾踢掉一些垃圾。由于每个垃圾最多只会被加进集合一次,踢出集合一次,所以复杂度十分的正确。
那么接下来考虑如何快速计算集合内的答案。
我们考虑记
下一步考虑加入一个新的垃圾进入集合,会对哪些
这个很容易就能推出来,当加入了一个纵坐标为
发现这是一个十分简单的区间修改,搞个线段树,发现这个纵坐标有点大,搞个离散化。
code
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,w,h;
const int N=1e5+5;
struct point
{
int x,y,w;
int ly,hy;
}a[N];
int b[N<<1];
int tot;
inline bool operator<(point a,point b)
{
return a.x^b.x?a.x<b.x:a.y^b.y?a.y<b.y:a.w<b.w;
}
struct sgt
{
int lar[N<<2],add[N<<2];
#define lx (x<<1)
#define rx (x<<1|1)
#define mid (L+R>>1)
inline void up(int x)
{
lar[x]=max(lar[lx],lar[rx]);
return;
}
inline void tag(int x,int L,int R)
{
if(add[x])
{
lar[lx]+=add[x];
lar[rx]+=add[x];
add[lx]+=add[x];
add[rx]+=add[x];
add[x]=0;
}
return;
}
void update(int x,int L,int R,int l,int r,int v)
{
if(l<=L&&R<=r){lar[x]+=v,add[x]+=v;return;}
tag(x,L,R);
if(l<=mid)update(lx,L,mid,l,r,v);
if(r>mid)update(rx,mid+1,R,l,r,v);
up(x);
return;
}
}subaru;
int ans;
signed main()
{
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>w>>h;
for(int i=1;i<=n;++i)cin>>a[i].x>>a[i].y>>a[i].w,b[++tot]=a[i].y,b[++tot]=a[i].y-h+1;
sort(a+1,a+1+n);
sort(b+1,b+1+tot);
tot=unique(b+1,b+1+tot)-b-1;
for(int i=1;i<=n;++i)a[i].ly=lower_bound(b+1,b+1+tot,a[i].y-h+1)-b,a[i].hy=lower_bound(b+1,b+1+tot,a[i].y)-b;
for(int i=1,j=1;i<=n;++i)
{
subaru.update(1,1,n,a[i].ly,a[i].hy,a[i].w);
while(a[j].x+w-1<a[i].x)subaru.update(1,1,n,a[j].ly,a[j].hy,-a[j].w),++j;
ans=max(ans,subaru.lar[1]);
}
cout<<ans;
return 0;
}