bzoj 2209: [Jsoi2011]括号序列 splay
2209: [Jsoi2011]括号序列
Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 833 Solved: 392
[Submit][Status]
Description
![](http://www.lydsy.com/JudgeOnline/images/2209.jpg)
Input
输入数据的第一行包含两个整数N和Q,分别表示括号序列的长度,以及操作的个数。 第二行包含一个长度为N的括号序列。 接下来Q行,每行三个整数t、x和y,分别表示操作的类型、操作的开始位置和操作的结 束位置,输入数据保证x不小于y。其中t=0表示询问操作、t=1表示反转操作、t=2表示翻转操 作。
Output
对于每一个询问操作,输出一行,表示将括号序列的该子序列修改为配对,所需的最少改动 个数。
Sample Input
6 3
)(())(
0 1 6
0 1 4
0 3 4
)(())(
0 1 6
0 1 4
0 3 4
Sample Output
2
2
0
2
0
HINT
100%的数据满足N,Q不超过10^5
终于算是会写splay了,这道题涉及到splay的区间翻转,取反,询问以及lazy标记下放等操作,算是涵盖了splay的基本用法。
合法的括号序列的一个性质是,以正括号为1,反括号为-1,合法序列和为0,且所有前缀权值和非负。顾可以通过类似于线段树求区间最大子段和方式维护,由于涉及到区间翻转,故改为splay维护。
这次编写问题还是在标记同步上,具体来说,在get_kth()调用前一定要down(),修改子树后要讲修改后的值传回根节点。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MAXN 210000 #define MAXT 210000 inline int min(int x,int y,int z) { return min(x,min(y,z)); } inline int min(int a,int b,int c,int d) { return min(min(a,b),min(c,d)); } inline int max(int x,int y,int z) { return max(x,max(y,z)); } inline int max(int a,int b,int c,int d) { return max(max(a,b),max(c,d)); } int num[MAXN]; struct splay_tree { int ch[MAXT][2],pnt[MAXT]; int val[MAXT],siz[MAXT],sum[MAXT],lx[MAXT][2],rx[MAXT][2]; bool rev[MAXT],neg[MAXT]; int stack[MAXT],tops; int topt; int root; splay_tree() { topt=0,root=0; tops=-1; } void reverse(int now) { if (!now)return; swap(lx[now][0],rx[now][0]); swap(lx[now][1],rx[now][1]); swap(ch[now][0],ch[now][1]); rev[now]^=1; } void negate(int now) { if (!now)return ; val[now]=-val[now]; sum[now]=-sum[now]; swap(lx[now][0],lx[now][1]); swap(rx[now][0],rx[now][1]); lx[now][0]=-lx[now][0]; rx[now][0]=-rx[now][0]; lx[now][1]=-lx[now][1]; rx[now][1]=-rx[now][1]; neg[now]^=1; } void update(int now) { lx[now][0]=min(lx[ch[now][0]][0],sum[ch[now][0]],sum[ch[now][0]]+val[now],sum[ch[now][0]]+val[now]+lx[ch[now][1]][0]); lx[now][1]=max(lx[ch[now][0]][1],sum[ch[now][0]],sum[ch[now][0]]+val[now],sum[ch[now][0]]+val[now]+lx[ch[now][1]][1]); rx[now][0]=min(rx[ch[now][1]][0],sum[ch[now][1]],sum[ch[now][1]]+val[now],sum[ch[now][1]]+val[now]+rx[ch[now][0]][0]); rx[now][1]=max(rx[ch[now][1]][1],sum[ch[now][1]],sum[ch[now][1]]+val[now],sum[ch[now][1]]+val[now]+rx[ch[now][0]][1]); sum[now]=sum[ch[now][0]]+sum[ch[now][1]]+val[now]; siz[now]=siz[ch[now][0]]+siz[ch[now][1]]+1; } void down(int now) { if (rev[now]) { reverse(ch[now][0]); reverse(ch[now][1]); rev[now]=0; } if (neg[now]) { negate(ch[now][0]); negate(ch[now][1]); neg[now]=0; } } void rotate(int now) { int p=pnt[now],anc=pnt[p]; int dir=ch[p][0]==now; if (anc) ch[anc][ch[anc][1]==p]=now; pnt[now]=anc; pnt[ch[now][dir]]=p; ch[p][1-dir]=ch[now][dir]; pnt[p]=now; ch[now][dir]=p; update(p); update(now); } void splay(int now,int tp=0) { int x=now; tops=-1; while (x!=tp) { stack[++tops]=x; x=pnt[x]; } while (~tops) { down(stack[tops--]); } while (now!=tp && pnt[now]!=tp) { int p=pnt[now],anc=pnt[p]; if (anc==tp) rotate(now); else if ((ch[p][0]==now) == (ch[anc][0]==p)) rotate(p),rotate(now); else rotate(now),rotate(now); } if (tp==0) root=now; } int get_kth(int now,int rk) { if (!now)throw 1; down(now); if (siz[ch[now][0]]+1==rk) return now; if (siz[ch[now][0]]+1<rk) return get_kth(ch[now][1],rk-siz[ch[now][0]]-1); else return get_kth(ch[now][0],rk); } void insert(int pos,int v) { if (!root) { root=++topt; pnt[topt]=0; val[topt]=v; update(topt); }else if (!pos) { splay(get_kth(root,pos)); ch[root][0]=topt; pnt[topt]=root; val[topt]=v; update(topt); update(root); }else { splay(get_kth(root,pos)); val[++topt]=v; pnt[topt]=root; ch[topt][1]=ch[root][1]; pnt[ch[root][1]]=topt; ch[root][1]=topt; update(topt); update(root); } } int get_result(int now) { int res=0,t; t=-lx[now][0]; res=t/2+t%2; t=res*2+sum[now]; res+=abs(t)/2; return res; } int query(int l,int r) { if (l==1 && r==siz[root]) return get_result(root); if (l==1) { splay(get_kth(root,r+1)); return get_result(ch[root][0]); } if (r==siz[root]) { splay(get_kth(root,l-1)); return get_result(ch[root][1]); } splay(get_kth(root,r+1)); splay(get_kth(root,l-1),root); return get_result(ch[ch[root][0]][1]); } void make_reverse(int l,int r) { if (l==1 && r==siz[root]) return reverse(root); if (l==1) { splay(get_kth(root,r+1)); reverse(ch[root][0]); update(root); return ; } if (r==siz[root]) { splay(get_kth(root,l-1)); reverse(ch[root][1]); update(root); return ; } splay(get_kth(root,r+1)); splay(get_kth(root,l-1),root); reverse(ch[ch[root][0]][1]); update(ch[root][0]); update(root); } void make_negate(int l,int r) { if (l==1 && r==siz[root]) return negate(root); if (l==1) { splay(get_kth(root,r+1)); negate(ch[root][0]); update(root); return ; } if (r==siz[root]) { splay(get_kth(root,l-1)); negate(ch[root][1]); update(root); return ; } splay(get_kth(root,r+1)); splay(get_kth(root,l-1),root); negate(ch[ch[root][0]][1]); update(ch[root][0]); update(root); } void scan(int now) { if (!now)return ; if (pnt[ch[now][0]]!=now && ch[now][0])throw 1; if (pnt[ch[now][1]]!=now && ch[now][1])throw 2; if (siz[now]!=siz[ch[now][0]]+siz[ch[now][1]]+1)throw 3; scan(ch[now][0]); printf("%d ",val[now]); scan(ch[now][1]); } }pp; int main() { //freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); int n,m,i,j,k,x,y,z; scanf("%d%d\n",&n,&m); char ch; for (i=1;i<=n;i++) { scanf("%c",&ch); if (ch==')') pp.insert(i-1,-1); else pp.insert(i-1,1); } int opt; for (i=1;i<=m;i++) { scanf("%d%d%d",&opt,&x,&y); // pp.scan(pp.root);printf("\n"); if (opt==0) { printf("%d\n",pp.query(x,y)); }else if (opt==1) { pp.make_negate(x,y); }else if (opt==2) { pp.make_reverse(x,y); } } }
by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载
本博客已停用,新博客地址:http://mhy12345.xyz