2018.09.22 atcoder Snuke's Coloring 2(线段树+单调栈)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82817698

传送门
就是给出一个矩形,上面有一些点,让你找出一个周长最大的矩形,满足没有一个点在矩形中。
这个题很有意思。
考虑到答案一定会穿过中线。
于是我们可以把点分到中线两边。
先想想暴力如何解决。
显然就是枚举矩形的上下边的坐标然后求两边的最大宽度。
用单调栈搞一下这样的效率是 O ( n 2 ) O(n^2) 的。
考虑继续优化。
干脆我们只枚举一条边,另外一条用线段树维护最值。
代码:

#include<bits/stdc++.h>
#define N 300005
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
int w,h,n,top1,top2,ans;
struct Pot{int x,y;}p[N];
struct Node{int l,r,mx,add;}T[N<<2];
struct node{int id,val;}stk1[N],stk2[N];
inline int max(int a,int b){return a>b?a:b;}
inline void pushnow(int p,int v){T[p].mx+=v,T[p].add+=v;}
inline void build(int p,int l,int r){
	T[p].l=l,T[p].r=r,T[p].mx=T[p].add=0;
	if(l==r)return;
	build(lc,l,mid),build(rc,mid+1,r);
}
inline void update(int p,int ql,int qr,int v){
	if(T[p].l>qr||T[p].r<ql)return;
	if(ql<=T[p].l&&T[p].r<=qr)return pushnow(p,v);
	if(T[p].add)pushnow(lc,T[p].add),pushnow(rc,T[p].add),T[p].add=0;
	if(qr<=mid)update(lc,ql,qr,v);
	else if(ql>mid)update(rc,ql,qr,v);
	else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
	T[p].mx=max(T[lc].mx,T[rc].mx);
}
inline void swap(int&x,int&y){x^=y,y^=x,x^=y;}
inline bool cmp(Pot a,Pot b){return a.x<b.x;}
inline void solve(){
	sort(p+1,p+n+1,cmp),build(1,1,n),top1=top2=0;
	for(int i=1;i<=n;++i){
		int las=i-1;
		if(p[i].y<=h/2){
			while(top1&&stk1[top1].val<p[i].y){
				update(1,stk1[top1].id,las,stk1[top1].val-p[i].y);
				las=stk1[top1--].id-1;
			}
			if(las!=i-1)stk1[++top1]=(node){las+1,p[i].y};
		}
		else{
			while(top2&&stk2[top2].val>p[i].y){
				update(1,stk2[top2].id,las,p[i].y-stk2[top2].val);
				las=stk2[top2--].id-1;
			}
			if(las!=i-1)stk2[++top2]=(node){las+1,p[i].y};
		}
		stk1[++top1]=(node){i,0},stk2[++top2]=(node){i,h};
		update(1,i,i,h-p[i].x),ans=max(ans,T[1].mx+p[i+1].x);
	}
}
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
int main(){
	w=read(),h=read(),n=read();
	for(int i=1;i<=n;++i)p[i].x=read(),p[i].y=read();
	p[++n]=(Pot){0,0},p[++n]=(Pot){w,h};
	solve();
	for(int i=1;i<=n;++i)swap(p[i].x,p[i].y);
	swap(w,h);
	solve();
	cout<<ans*2;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/82817698
今日推荐