线段树+扫描线+离散化
给出星空中的一些星星的位置以及亮度,求放置一个给定的矩形使得矩形框住的星星的亮度最大
位置<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;
}