线段树+扫描线+离散化
给出星空中的一些星星的位置以及亮度,求放置一个给定的矩形使得矩形框住的星星的亮度最大
位置<2^32 星星个数<1e5 每个星星的亮度不超过100 矩形的长宽不超过 1e6
首先因为星星的个数比较小,位置的坐标比较大,可以想到离散化
然后想到一个叫做矩形面积并的东西,想到是不是可以扫描线一下
然后发现是可以的
再然后就是怎么处理星星的亮度了
如果直接将星星的亮度加到它的坐标上,那么去寻找一个覆盖的星星亮度最多的区间并不是很好写
我们换一个思路,定义val[i] 将矩形的左边界放在i点时能覆盖的星星的亮度和,那么每一个星星能更新的位置是一段连续的区间
每一次询问就是查询总区间中最大的一个点,然后就很好做了(也就是线段树的区间覆盖区间查询
感觉中间的这个思路转换好厉害,特此记下来
#include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<map> using namespace std; const int maxn = 112345; #define lson o<<1,l,m #define rson o<<1|1,m+1,r #define root 1,1,maxn*2 #define Now int o,int l,int r #define Mid int m = l + (r-l)/2 #define LL long long LL arr[maxn*8]; LL lazy[maxn*8]; void init(){ memset(arr,0,sizeof(arr)); memset(lazy,0,sizeof(lazy)); } void push_down(Now){ int v = lazy[o]; lazy[o] = 0; if(l != r){ lazy[o<<1]+=v; lazy[o<<1|1]+=v; arr[o<<1]+=v; arr[o<<1|1]+=v; } } void update(Now,int ul,int ur,int v){ if(ul <= l && r <= ur){ lazy[o]+=v; arr[o]+=v; return; } if(lazy[o]!=0) push_down(o,l,r); Mid; if(ul <= m){ update(lson,ul,ur,v); } if(m+1 <= ur){ update(rson,ul,ur,v); } arr[o] = max(arr[o<<1],arr[o<<1|1]); } struct event{ LL val; LL l,r; LL tim; void init(LL v,LL L,LL R,LL t){ val = v; l = L,r = R; tim = t; } }; event node[maxn * 2]; bool cmp(event a,event b){ if(a.tim != b.tim) return a.tim < b.tim; return a.val < b.val; } LL ranks[maxn*2]; int calrank(LL x,int sizer){ return lower_bound(ranks,ranks+sizer,x)-ranks; } int main(){ int n,w,h; while(~scanf("%d %d %d",&n,&w,&h)){ int len = 0; int sizer = 0; LL x,y; int v; init(); while(n--){ scanf("%lld %lld %d",&x,&y,&v); ranks[sizer++] = y; ranks[sizer++] = y+h-1; node[len++].init(v,y,y+h-1,x); node[len++].init(-v,y,y+h-1,x+w); } ranks[sizer++] = -1; sort(node,node+len,cmp); sort(ranks,ranks+sizer); LL ans = 0; for(int i=0;i<len;i++){ int l,r; l = calrank(node[i].l,sizer); r = calrank(node[i].r,sizer); update(root,l,r,node[i].val); ans = max(ans,arr[1]); } printf("%lld\n",ans); } return 0; }