• 【题解】窗口的星星


    前置芝士 扫描线#

    题目链接

    题目大意就是,问窗口能框住的最大亮度。

    转化一下题意,把每一颗星星扩展为一个长宽为(H,W)的矩形,在矩形里面,都是可以框住这颗星星的。

    那么问题就转化为,求一些矩形的最大面积并。

    显然扫描线做。线段树维护区间加的亮度,同时维护(MAX),查询的时候,一次次加边,一次次更新答案即可。

    注意数据大,需要离散化。用(sort,unique)就很方便。

    其中,我的(LowerBound)是手写的(find)函数。

    (Code:)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define int long long
    const int MAXN=5000000;
    int T,n,tot,rec,val[MAXN];
    int rk[MAXN],W,H,Ans,ans;
    struct SegmentTree{
    	int l,r,tag,v;
    }tr[MAXN];
    struct Line{
    	int l,h,v,x;
    	bool operator<(const Line&A)const{
    		return h<A.h;
    	}
    }e[MAXN];
    void build(int l,int r,int x){
    	tr[x].l=l;
    	tr[x].r=r;
    	tr[x].tag=tr[x].v=0;
    	if(l==r)return;
    	int mid=l+r>>1;
    	build(l,mid,x<<1);
    	build(mid+1,r,x<<1|1);
    }
    inline void pushdown(int x){
    	if(tr[x].tag){
    		tr[x<<1].tag+=tr[x].tag;
    		tr[x<<1|1].tag+=tr[x].tag;
    		tr[x<<1].v+=tr[x].tag;
    		tr[x<<1|1].v+=tr[x].tag;
    		tr[x].tag=0;
    	}
    }
    void change(int x,int l,int r,int k){
    	if(tr[x].l>=l&&tr[x].r<=r){
    		tr[x].tag+=k;
    		tr[x].v+=k;
    		pushdown(x);
    		return;
    	}
    	pushdown(x);
    	int mid=(tr[x].l+tr[x].r)>>1;
    	if(l<=mid)change(x<<1,l,r,k);
    	if(mid<r)change(x<<1|1,l,r,k);
    	tr[x].v=max(tr[x<<1].v,tr[x<<1|1].v);
    }
    inline bool cmp(Line A,Line B){
    	if(A.x==B.x)return A.v>B.v;
    	else return A.x<B.x; 
    }
    int find(int x){
    	int l=1,r=rec,A;
    	while(l<=r){
    		int mid=l+r>>1;
    		if(rk[mid]==x)return mid;
    		else if(rk[mid]>x)r=mid-1,A=r;
    		else if(rk[mid]<x)l=mid+1,A=l;
    	}
    	return A;
    }
    void query(int x,int l,int r){
    	if(tr[x].l>=l&&tr[x].r<=r){
    		ans=max(ans,tr[x].v);
    		return;
    	}
    	pushdown(x);
    	int mid=tr[x].l+tr[x].r>>1;
    	if(l<=mid)query(x<<1,l,r);
    	if(mid<r)query(x<<1|1,l,r);
    }
    signed main(){
    	scanf("%lld",&T);
    	while(T--){
    		n=W=H=0;
    		tot=0,rec=0,Ans=0,ans=0;
    		memset(val,0,sizeof(val));
    		memset(rk,0,sizeof(rk));
    		scanf("%lld%lld%lld",&n,&W,&H);
    		for(int i=1,x,y,v;i<=n;++i){
    			scanf("%lld%lld%lld",&x,&y,&v);
    			int x1=x-W,y1=y-1,x2=x-1,y2=y-H;
    			e[(i<<1)-1].x=x1,e[i<<1].x=x2;
    			e[(i<<1)-1].h=e[i<<1].h=y2;
    			e[(i<<1)-1].l=e[i<<1].l=y1;
    			e[(i<<1)-1].v=v;e[i<<1].v=-v;
    			rk[++tot]=y1,rk[++tot]=y2;
    		}
    		sort(rk+1,rk+tot+1);
    		rec=unique(rk+1,rk+tot+1)-rk-1;
    		for(int i=1;i<=(n<<1);++i){
    			int pos1=find(e[i].h);
    			int pos2=find(e[i].l);
    			val[pos1]=e[i].h;
    			val[pos2]=e[i].l;
    			e[i].h=pos1;e[i].l=pos2;
    		}
    		sort(e+1,e+(n<<1|1),cmp);
    		build(1,(n<<1),1); 
    		for(int i=1;i<=(n<<1);++i){
    			change(1,e[i].h,e[i].l,e[i].v);
    			query(1,e[i].h,e[i].l);
    			Ans=max(Ans,ans);
    		}
    		printf("%lld
    ",Ans);
    	}
    	return 0;
    }
    

    有时间准备扫描线讲解,准备历史去(QAQ)

  • 相关阅读:
    【SDOI2015】星际战争
    【雅礼联考DAY02】Magic
    【SDOI2015】排序
    【雅礼联考DAY01】逃跑
    【雅礼联考DAY01】数列
    【雅礼联考DAY02】Revolution
    Philips and Calculator
    maven整理——初步
    等价类划分方法分析与应用
    @Autowired
  • 原文地址:https://www.cnblogs.com/h-lka/p/11469841.html
Copyright © 2020-2023  润新知