您的位置:首页 > 其它

POJ 2482 Stars in Your Window (线段树扫描线)

2015-08-14 17:08 549 查看


题意:

给定n个星星的坐标(x,y)以及亮度c ,求用一个宽W,高H的框(不含边界),能框住的星星的亮度总和的最大值为多少。

( 0<= x,y <2^31 , 1<=c<=100    , 1<=W , H <= 1000000    ,   x,y,c,W,H都是整数)

思路:

用矩形右上角坐标(X,Y)来代表矩形位置,原问题等价于,X,Y为整数,用一个宽W,高H的框(不含左,下边界),能框住的星星的亮度总和的最大值为多少。因为,若X,Y为整数,并且四边上都有星星,那么将该方框向右和上分别平移1/2个单位,就可以在不丢失框内星星的情况下框进上边框和右边框的星星。

转换之后,对于星星(x,y),矩形的右上角坐标的范围在 x-[x,x+W), y-[y,y+H) 这个区域内时,算作框进了这颗星星,要算上这颗星星的亮度。

于是,星星变成了带权值的矩形,矩形框变成了点,问题就是在矩形的重合图中,找到权值最大的点。

这就可以用线段树扫描线了,就是,用一条垂直于x轴的线来从左到右扫描整个图形。整个扫描过程中,线上权值最大的一点就是答案。

线上的权值需要进行区间修改以及维护最大值,这里就用线段树来储存。

将Y值离散化(去除重复值),然后,将星星先根据X值,再根据Y值排序。

然后不断将新的矩形加入,旧的矩形删除就行了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define inf 0x1fffffff
#define maxn 20007
#define LL long long
using namespace std;
//SBT 离散化
LL Rank[maxn],Rn;
void SetRank(){
sort(Rank+1,Rank+1+Rn);
int I=1;
for(int i=2;i<=Rn;++i) if(Rank[i]!=Rank[i-1]) Rank[++I]=Rank[i];
Rn=I;
}
int GetRank(LL x){
int L=1,R=Rn,M;//[L,R] first >=x
while(L!=R){
M=(L+R)>>1;
if(Rank[M]<x) L=M+1;
else R=M;
}
return L;
}
//储存数据
struct Star{//记录星星,之后要排序
LL x,y;int c;
Star(){}
Star(LL x,LL y,int c):x(x),y(y),c(c){}
bool operator < (const Star &B)const{
return x < B.x|| x==B.x && y < B.y;
}
}St[maxn>>1];
int n,W,H;
//线段树 区间加&&最大值
int Max[maxn<<2],Add[maxn<<2];
void PushUp(int rt){
Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void PushDown(int rt){
if(Add[rt]){
Add[rt<<1]+=Add[rt];Add[rt<<1|1]+=Add[rt];
Max[rt<<1]+=Add[rt];Max[rt<<1|1]+=Add[rt];
Add[rt]=0;
}
}
void Update(int L,int R,int C,int l,int r,int rt){
if(L <=l && r <= R){Add[rt]+=C;Max[rt]+=C;return;}
PushDown(rt);
int m=(l+r)>>1;
if(L <= m) Update(L,R,C,l,m,rt<<1);
if(R > m) Update(L,R,C,m+1,r,rt<<1|1);
PushUp(rt);
}
int main(void)
{
while(~scanf("%d%d%d",&n,&W,&H)){
memset(Max,0,sizeof(Max));
memset(Add,0,sizeof(Add));
Rn=0;
for(int i=1;i<=n;++i) {
scanf("%I64d%I64d%d",&St[i].x,&St[i].y,&St[i].c);
Rank[++Rn]=St[i].y;
Rank[++Rn]=St[i].y+H;
}
SetRank();
sort(St+1,St+n+1);//给星星排序
int L=1,X,ANS=0;
for(int i=1;i<=n;++i){
Update(GetRank(St[i].y),GetRank(St[i].y+H)-1,St[i].c,1,Rn,1);//加入新矩形
X=St[i].x;//更新当前X
while(St[L].x+W <= X){//删除已经对横坐标为X的扫描线无影响的矩形
Update(GetRank(St[L].y),GetRank(St[L].y+H)-1,-St[L].c,1,Rn,1);
++L;
}
ANS=max(ANS,Max[1]);//求最大值
}
printf("%d\n",ANS);//输出答案
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树 poj