【题解】窗口的星星

前置芝士 扫描线#

题目链接

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

转化一下题意,把每一颗星星扩展为一个长宽为\(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\n",Ans);
	}
	return 0;
}

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

posted @ 2019-09-05 21:13  Refined_heart  阅读(192)  评论(0编辑  收藏  举报