专栏文章

题解:P12119 [NordicOI 2025] 垃圾收集 / Garbage Collection

P12119题解参与者 5已保存评论 7

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
7 条
当前快照
1 份
快照标识符
@mipe9w89
此快照首次捕获于
2025/12/03 10:35
3 个月前
此快照最后确认于
2025/12/03 10:35
3 个月前
查看原文

思路

我们考虑将垃圾按 xx 排序,然后维护一个集合,使这个集合中的最大的横坐标之差不大于 WW
这个集合的维护是简单的,从左往右扫,每次遇到一个新的垃圾就去集合末尾踢掉一些垃圾。由于每个垃圾最多只会被加进集合一次,踢出集合一次,所以复杂度十分的正确。
那么接下来考虑如何快速计算集合内的答案。
我们考虑记 lil_i 表示我们能选择的矩形的靠下的那条边纵坐标为 ii 时,能捞到的垃圾重量之和。
下一步考虑加入一个新的垃圾进入集合,会对哪些 lil_i 产生影响。
这个很容易就能推出来,当加入了一个纵坐标为 yiy_i 的新垃圾,那么当你的矩形最下面一条边的纵坐标 ii 满足 yiH+1iyiy_i-H+1\leq i \leq y_i 时,你就可以捞到这个垃圾。
发现这是一个十分简单的区间修改,搞个线段树,发现这个纵坐标有点大,搞个离散化。

code

CPP
#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;
}

评论

7 条评论,欢迎与作者交流。

正在加载评论...