题意:已知每个星星的坐标和亮度,求用一个宽w,高h的矩形能圈住的星星的亮度总和最大是多少。
思路:我们把每个星星置为w,h矩形的左下角,这样围才是最多的情况。然后将每个这样的搞出来并把其矩形赋权为其亮度,可以发现当两个矩形重合的地方就可以用亮度加起来
表示,因为在那个地方做宽w高h的矩形两个星星都圈的起来。所以问题就又变成了求坐标上重叠区域的最大权值和。
根据扫描线,我们先对x坐标排序,设星星(x,y,c)c为亮度,保存两个四元组(x,y,y+h-1,c)和(x+w,y,y+h-1,-c)。维护对于当前x,y坐标整点上权值和的最大值。区间修改+c,-c就相当于
只在x到x+c的区间内亮度+c。
#include<cstring> #include<algorithm> #include<vector> #include<map> #include<queue> #include<cstdio> #include<cmath> #define int long long #define lowbit(x) x&(-x) using namespace std; const int N=2e4+10; struct node{ int x,y1,y2; int c; node() {} node(int x, int y1,int y2,int c){ this->x = x; this->c = c; this->y1 = y1; this->y2 = y2; } bool operator <(const node &t)const { return x<t.x; } }a[N]; int n,w,h,y[N]; struct Tree { int l,r; int len,lazy; }t[N<<2]; void pushup(int p) { t[p].len=max(t[p<<1].len,t[p<<1|1].len)+t[p].lazy; } void build(int p,int l,int r) { t[p].l=y[l]; t[p].r=y[r]; t[p].lazy=0; t[p].len=0; if(r-l==1) { return; } int mid=(l+r)>>1; build(p<<1,l,mid); build(p<<1|1,mid,r); } void update(int l,int r,int k,int p) { if(t[p].l>=l&&t[p].r<=r) { t[p].lazy+=k; t[p].len+=k; return; } if(l<t[p<<1].r) update(l,min(r,t[p<<1].r),k,p<<1); if(r>t[p<<1|1].l) update(max(l,t[p<<1|1].l),r,k,p<<1|1); pushup(p); } signed main() { while(~scanf("%lld%lld%lld",&n,&w,&h)) { int cnt=0,num=1; for(int i=1;i<=n;i++) { int xx,yy,k; scanf("%lld%lld%lld",&xx,&yy,&k); a[cnt++]=node(xx,yy,yy+h,k); a[cnt++]=node(xx+w,yy,yy+h,-k); y[num++]=yy; y[num++]=yy+h; } sort(y+1,y+num); int ans=0; num=unique(y+1,y+num)-(y+1); sort(a,a+cnt); build(1,1,num); for(int i=0; i<cnt; i++) { update(a[i].y1,a[i].y2,a[i].c,1); if(a[i].c>0) ans=max(ans,t[1].len); } printf("%lld ",ans); } return 0; }