zoukankan      html  css  js  c++  java
  • POJ 2482 & caioj 2059& CH 0x40数据结构进阶(0x43 线段树)例题5:你窗外的星星

    我们先把题意转化一下,用whw*h的矩形框(不能取边界)等价于用(w1)(h1)(w-1)*(h-1)的矩形框(能取边界).
    为什么?
    因为合法星星集合中两两星星水平方向上的距离是不能大于w的,那么我们就证明为什么能把差为(w-1)的框进去.
    如图:
    在这里插入图片描述
    我们把矩形的顶点挪到方格中心就行了嘛.h类似.

    (之后的说法都按变化后的题意来,并且默认w和h都减了1)

    因为矩形长宽固定,所以只要确定一个点的位置和点与点之间的相对位置,我们就能唯一确定它.
    (讲得不清不楚 ).举个例子,只要确定右上角顶点,就能确定矩形.
    所以我们可以考虑吧矩形的右上角放在哪个位置,框住星星的亮度总和最大.

    能把一个坐标为(x,y)(x,y)的星星框住的矩形的右上角坐标(x1,y1)(x_1,y_1)必须满足
    x1[x,x+w],y1[y,y+h]x_1in [x,x+w] ,y_1in[y,y+h].
    我们假想出1个框,表示能把一个星星包住的右上角合法位置(框的边界也算)
    如图:

    再次提醒:w,hw,h默认已减1

    多个点的话会出现下面的情况:

    在这里插入图片描述
    重叠部分表示矩形的右上角在那儿时,可把多个星星包住.
    此时,我们可以把问题转化为:平面有多个区域,每个区域有一个权值(重叠部分权值累加),求最大权值

    (一点扫描线的痕迹都没有)
    我们假设有一条扫描线从左往右扫过,那么每个假设的框的左边就为入边,右边为出边.
    我们把yy坐标离散化一下,再把边按xx排序一下,就可以做了.
    假设的框的边界是可取的,所以点就不必转成段了.
    线段树维护的是区间最大值.要用到延迟操作.
    排序有点小细节,需要仔细理解.

    说得不清不楚,所以重点看代码.

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define g getchar()
    #define lc (x<<1)
    #define rc (x<<1|1)
    using namespace std;
    const int N=10010;
    
    int n,w,h,m;
    
    struct line {
    	int x,y,z,k;
    	bool operator <(line b) const {
    		return x!=b.x?x<b.x:k<b.k;
    	}
    }a[N<<1];
    
    int raw[N<<1];
    void disc() {
    	sort(raw+1,raw+n+1); m=1;
    	for(int i=2;i<=n;i++) 
    		if(raw[i]!=raw[m]) raw[++m]=raw[i];
    }
    
    int val(int x) {
    	int l=1,r=m,mid;
    	while(l<r) {
    		int mid=(l+r)>>1;
    		if(raw[mid]<x)l=mid+1;
    		else r=mid;
    	}
    	return l;
    }
    
    struct node {
    	int mx,ad;
    }tr[N<<3];
    
    void bt(int x,int l,int r) {
    	tr[x].mx=tr[x].ad=0;
    	if(l==r)return ;
    	int mid=(l+r)>>1;
    	bt(lc,l,mid);
    	bt(rc,mid+1,r);
    }
    
    int lazy(int x,int l,int r) {
    	int mid=(l+r)>>1;
    	if(tr[x].ad) {
    		tr[lc].ad+=tr[x].ad; tr[lc].mx+=tr[x].ad;
    		tr[rc].ad+=tr[x].ad; tr[rc].mx+=tr[x].ad;
    		tr[x].ad=0;
    	}
    	return mid;
    }
    
    void add(int x,int l,int r,int L,int R,int d) {
    	if(L<=l&&r<=R) {
    		tr[x].ad+=d;
    		tr[x].mx+=d;
    		return ;
    	}
    	int mid=lazy(x,l,r);
    	if(L<=mid) add(lc,l,mid,L,R,d);
    	if(mid< R) add(rc,mid+1,r,L,R,d);
    	tr[x].mx=max(tr[lc].mx,tr[rc].mx);
    }
    
    void qr(int &x) {
    	char c=g;x=0;int f=1;
    	while(!isdigit(c)){if(c=='-')f=-1; c=g;}
    	while(isdigit(c))x=x*10+c-'0',c=g;
    	x*=f;
    }
    
    int main() {
    	while(~scanf("%d%d%d",&n,&w,&h)) {
    		for(int i=1,j=2;i<=n;i++,j+=2) {
    			int x,y,c;qr(x);qr(y);qr(c);
    			a[j-1]=(line){x,y,y+h-1,c};
    			a[j	 ]=(line){x+w,y,y+h-1,-c};
    			raw[j-1]=y;raw[j]=y+h-1;
    		}
    		n<<=1; disc(); sort(a+1,a+n+1);
    		bt(1,1,m-1); int ans=0;
    		for(int i=1;i<=n;i++) {
    			int y=val(a[i].y),z=val(a[i].z)-1;
    			add(1,1,m-1,y,z,a[i].k);
    			ans=max(ans,tr[1].mx);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    	
    
  • 相关阅读:
    设计模式笔记(22)状态模式(行为型)
    设计模式笔记(16)解释器模式(行为型)
    Lable和Literal控件的使用和区别
    设计模式笔记(15)命令模式(行为型)
    设计模式笔记(25)总结
    在JS方法中返回多个值的三种方法
    SQL 左外连接,右外连接,全连接,内连接
    面试集萃
    ASP.NET MVC如何使用Ajax的辅助方法
    ASP.NET MVC+EF框架+EasyUI实现权限管理(附源码)
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373901.html
Copyright © 2011-2022 走看看