POJ 2482 Stars in Your Window(扫描线法、线段树区间加维护最大值、离散化)

POJ 2482 Stars in Your Window

蓝书线段树练习题
POJ 2482 Stars in Your Window

题意:给定 n n n个星星,长 w w w h h h的框框。每个星星给定坐标 ( x , y ) (x,y) (x,y),亮度 c c c。问框内最大的亮度和。(边界上的亮度不记)

数据范围: n : 1 e 4 , w / h : 1 e 6 , x / y : 2 31 n:1e4,w/h:1e6,x/y:2^{31} n1e4w/h:1e6,x/y:231

思路:

  • 问题转换:能够圈主第i个星星的框框位置构成了一个方块,假设星星坐标为 ( x , y ) (x,y) (x,y),则能够圈住的两个边界为 ( x , y , y + h ) , ( x + w , y , y + h ) (x,y,y+h),(x+w,y,y+h) (x,y,y+h),(x+w,y,y+h)
  • 考虑边界问题(在边边上的星星不记入当前框):因为坐标为整数,将所有星星都从 ( x , y ) (x,y) (x,y)变为 ( x − 0.5 , y − 0.5 ) (x-0.5,y-0.5) (x0.5,y0.5),那么边界只要变成 ( x , y , y + h − 1 ) (x,y,y+h-1) (x,y,y+h1), ( x + w , y , y + h − 1 ) (x+w,y,y+h-1) (x+w,y,y+h1),那这个框框就圈住的星星就一定不在边界上。
  • 边界贡献:对于左边界 ( x , y , y + h − 1 ) (x,y,y+h-1) (x,y,y+h1)的贡献为 c i c_i ci,对于右边界 ( x + w , y , y + h − 1 ) (x+w,y,y+h-1) (x+w,y,y+h1)的贡献为 − c i -c_i ci
  • 具体算法
  1. 先储存每个边界的 ( x , y , z , c ) (x,y,z,c) (x,y,z,c)(z是每个边界的上顶点),对边界以x进行升序排序。
  2. 对每个 y y y(线段树的区间)进行离散化(数据范围太大,n比较小)
  3. 建树,遍历 2 n 2n 2n个边界进行区间加,维护区间最大值dat,每次根节点的dat就是当前边界位置的最大亮度,答案取所有边界根节点的最大。

注意开LL

LL n,w,h;
struct SegmentTree{
    
    
	int l,r;
	LL dat,add;
	#define l(x) tree[x].l
    #define r(x) tree[x].r
    #define dat(x) tree[x].dat
    #define add(x) tree[x].add
}tree[maxn*8];
struct node{
    
    
    LL x,y,z;
    LL c;
    bool operator <(const node aa)const{
    
    
        return x<aa.x||(x==aa.x&&c<aa.c);
    }
}a[maxn*2];
LL  b[maxn*2];

void build(int p,int l,int r){
    
    
	l(p)=l,r(p)=r;
	dat(p)=0;add(p)=0;
	if(l==r) {
    
    return;}
	int mid=(l+r)/2;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}

void lazy(int p){
    
    
	if(add(p)){
    
    
		dat(p*2)+=add(p);
		dat(p*2+1)+=add(p);
		add(p*2)+=add(p);
		add(p*2+1)+=add(p);
		add(p)=0;
	}
}

void change(int p,int l,int r,LL z){
    
    
	if(l<=l(p)&&r>=r(p)){
    
    
		dat(p)+=z;
		add(p)+=z;
		return;
	}
	lazy(p);
	int mid=(l(p)+r(p))/2;
	if(l<=mid) change(p*2,l,r,z);
    if(r>mid) change(p*2+1,l,r,z);
	dat(p)=max(dat(p*2),dat(p*2+1));
}

LL ask(int p,int l,int r)
{
    
    
	if(l<=l(p)&&r>=r(p)) return dat(p);
	lazy(p);
    int mid=(l(p)+r(p))/2;
	LL ans=0;
    if(l<=mid) ans+=ask(p*2,l,r);
    if(r>mid) ans+=ask(p*2+1,l,r);
    return ans;
}

int main(){
    
    
    LL co,ans;
    while(scanf("%lld%lld%lld",&n,&w,&h)!=EOF){
    
    
        ans=0ll;
        for(int i=1;i<=n;i++){
    
    
            scanf("%lld%lld%lld",&a[2*i-1].x,&a[2*i-1].y,&a[i*2-1].c);
            a[2*i].x=a[2*i-1].x+w;
            b[i*2-1]=a[2*i].y=a[2*i-1].y;
            b[2*i]=a[2*i].z=a[2*i-1].z=a[2*i-1].y+h-1;
            a[2*i].c=-1*a[2*i-1].c;
        }
        n*=2;
        sort(b+1,b+1+n);
        co=unique(b+1,b+1+n)-b-1;
        for(int i=1;i<=n;i++){
    
    
            a[i].y=lower_bound(b+1,b+co+1,a[i].y)-b;
            a[i].z=lower_bound(b+1,b+1+co,a[i].z)-b;
        }
        sort(a+1,a+1+n);
        build(1,1,co);
        for(int i=1;i<=n;i++){
    
    
            change(1,a[i].y,a[i].z,a[i].c);
            ans=max(ans,tree[1].dat);
        }
        cout<<ans<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44986601/article/details/105807204