1. 程式人生 > >●BZOJ 2209 [Jsoi2011]括號序列

●BZOJ 2209 [Jsoi2011]括號序列

static 個數 括號序列 struct borde ide sum oid dad

題鏈:

http://www.lydsy.com/JudgeOnline/problem.php?id=2209
題解: Splay 很好的題,但是把智障的我給惡心到了。。。 首先不難發現,最後沒有匹配的括號的樣子一定是 ))))..((((... 即左邊是右括號(設個數為nr),右邊是做括號(設個數為nl) 則答案為 ⌈nl÷2⌉ + ⌈nr÷2⌉ (⌈ ⌉:向上取整) 若把 ‘(‘ 看成 1,把 ‘)‘ 看成 -1, 那麽在這個只含有 1 和 -1 的序列裏,
前綴最小值的相反數就等於nr, 後綴最大值的就等於nl 所以對於詢問操作來說,在Splay中記錄: key[x](節點x是 1 還是 -1) sum[x](x子樹對應區間的sum和) pmn[x](x子樹對應區間的前綴最小值), smx[x](x子樹對應區間的後綴最大值)。 對於第二個反轉操作 可以看出,只是把對應區間的 1→ -1,-1→ 1, 所以再多維護兩個東西 pmx[x](x子樹對應區間的前綴最大值), smn[x](x子樹對應區間的後綴最小值)。 然後把記錄的 key[x],sum[x],pmn[x],pmx[x],smn[x],smx[x]全部取反(都乘上-1),
並且 swap(pmn[x],pmx[x]), swap(smn[x],smx[x])(因為取反了啊~) 再打個lazy標記,就好啦。 對於第三個翻轉操作 就只需交換左右子樹, 並且 swap(pmx[x],smx[x]),swap(pmn[x],smn[x]) (只是把序列反了起來,所以交換前後綴信息即可) 然後打一個lazy標記。 因為lazy標記不存在先後影響,所以lazy下放時隨便先放哪個都可以的。 代碼:
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 100500
using namespace std;
int N,M;
struct SPT{
	int pmx[MAXN],pmn[MAXN],smx[MAXN],smn[MAXN],sum[MAXN],key[MAXN];
	int ch[MAXN][2],siz[MAXN],fa[MAXN],lazy[MAXN],rt;
	void Reverse(int x){
		sum[x]*=-1; key[x]*=-1;
		pmx[x]*=-1; pmn[x]*=-1; swap(pmx[x],pmn[x]);
		smx[x]*=-1; smn[x]*=-1; swap(smx[x],smn[x]);
	}
	void Flip(int x){
		swap(pmx[x],smx[x]);
		swap(pmn[x],smn[x]);
		swap(ch[x][0],ch[x][1]);
	}
	void Pushup(int x){
		siz[x]=siz[ch[x][0]]+1+siz[ch[x][1]];
		sum[x]=sum[ch[x][0]]+key[x]+sum[ch[x][1]];
		pmx[x]=max(pmx[ch[x][0]],sum[ch[x][0]]+key[x]+pmx[ch[x][1]]);
		pmn[x]=min(pmn[ch[x][0]],sum[ch[x][0]]+key[x]+pmn[ch[x][1]]); 
		smx[x]=max(smx[ch[x][1]],sum[ch[x][1]]+key[x]+smx[ch[x][0]]);
		smn[x]=min(smn[ch[x][1]],sum[ch[x][1]]+key[x]+smn[ch[x][0]]);
	}
	void Pushdown(int x){
		if(lazy[x]&1){
			Reverse(ch[x][0]); lazy[ch[x][0]]^=1;
			Reverse(ch[x][1]); lazy[ch[x][1]]^=1;
			lazy[x]^=1;
		}
		if(lazy[x]&2){
			Flip(ch[x][0]); lazy[ch[x][0]]^=2;
			Flip(ch[x][1]); lazy[ch[x][1]]^=2;
			lazy[x]^=2;
		}
	}
	void Rotate(int x,int &k){
		static int y,z,l,r;
		y=fa[x]; z=fa[y];
		l=ch[y][0]!=x; r=l^1;
		if(!z) k=x;
		else ch[z][ch[z][0]!=y]=x;
		fa[ch[x][r]]=y; fa[y]=x; fa[x]=z;
		ch[y][l]=ch[x][r]; ch[x][r]=y;
		Pushup(y);
	}
	void Splay(int x,int &k){
		static int y,z;
		while(x!=k){
			y=fa[x]; z=fa[y];
			if(y!=k) (ch[z][0]!=y)^(ch[y][0]!=x)?
				Rotate(x,k):Rotate(y,k);
			Rotate(x,k);
		}
		Pushup(x);
	}
	int find(int x,int num){
		if(lazy[x]) Pushdown(x);
		if(num<=siz[ch[x][0]]) return find(ch[x][0],num);
		else if(num==siz[ch[x][0]]+1) return x;
		else return find(ch[x][1],num-siz[ch[x][0]]-1);
	}
	int Split(int l,int r){
		static int dl,dr;
		dl=find(rt,l); dr=find(rt,r+2);
		Splay(dl,rt); Splay(dr,ch[dl][1]);
		return ch[dr][0];
	}
	void Modify(int l,int r,int type){
		static int p;
		p=Split(l,r);
		if(type==1) Reverse(p);
		else Flip(p);
		lazy[p]^=type;
		Pushup(fa[p]); Pushup(fa[fa[p]]);
	}
	void Build(int &x,int dad,int l,int r){
		static char c;
		if(l>r) return;
		x=(l+r)>>1; fa[x]=dad;
		Build(ch[x][0],x,l,x-1);
		scanf(" %c",&c); key[x]=(c==‘(‘?1:-1);
		Build(ch[x][1],x,x+1,r);
		Pushup(x);
	}
	void BorderBuild(){
		rt=N+1;
		key[N+1]=0; key[N+2]=0;
		ch[N+1][1]=N+2; fa[N+2]=N+1;
		Build(ch[N+2][0],N+2,1,N);
		Pushup(N+2); Pushup(N+1);
	}
	int Query(int l,int r){
		static int p,ANS,nl,nr;
		p=Split(l,r);
		nl=-pmn[p]; nr=smx[p];
		ANS=(nl+1)/2+(nr+1)/2;
		return ANS;
	}
}DT;
int main(){
	freopen("/home/noilinux/Documents/模塊學習/2209.in","r",stdin);
	scanf("%d%d",&N,&M);
	DT.BorderBuild();
	for(int i=1,c,l,r;i<=M;i++){
		scanf("%d%d%d",&c,&l,&r);
		if(c==0) printf("%d\n",DT.Query(l,r));
		else DT.Modify(l,r,c);
	}
	return 0;
}

  

●BZOJ 2209 [Jsoi2011]括號序列