bzoj2329: [HNOI2011]括号修复(fhq treap)
http://www.lydsy.com/JudgeOnline/problem.php?id=2329
需要改变的括号序列一定长这样 :)))(((
最少改变次数= 多余的‘)’/2 【上取整】 + 多余的‘(’ /2 【上取整】
把 ‘)’ 看做1,‘(’ 看做-1
那么最少改变次数=最大前缀和/2 【上取整】+ 最小后缀和/2 【上取整】
覆盖标记的优先级高于翻转标记和取反标记
即下放覆盖标记时,同时清空翻转标记和取反标记
且先下放覆盖标记
翻转:
最大前缀和 和 最大后缀和 交换
最小前缀和 和 最小后缀和 交换
取反:
最大前缀和 和 最小前缀和 交换,同时取反
最大后缀和 和 最小后缀和 交换,同时取反
最大XX和的下界为0,最小XX和的上界为0
因为最大XX和实际是多余的‘)’数量
最小XX和的相反数实际是多余的‘(’数量
数量不能为负数
注意点:
1、增加了首尾两个虚拟节点后,数组要多开2
2、平衡树每个节点由三部分组成,左子树、自己、右子树,打取反标记的时候不要忘记给自己取反
#include<cstdio> #include<cstdlib> #include<iostream> using namespace std; #define N 100003 char ss[N]; int a[N]; int root,tot; int st[N]; bool rev[N],inv[N]; int tag[N]; int pre[N],suf[N]; int sum[N]; int pri[N],val[N]; int siz[N],ch[N][2]; int tmp; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } inline int &max(int &a,int &b) { return a>b ? a : b; } inline int &min(int &a,int &b) { return a<b ? a : b; } void update(int x) { int l=ch[x][0],r=ch[x][1]; siz[x]=siz[l]+siz[r]+1; sum[x]=sum[l]+sum[r]+val[x]; pre[x]=max(pre[l],sum[l]+pre[r]+val[x]); pre[x]=max(pre[x],sum[l]+val[x]); suf[x]=max(suf[r],sum[r]+suf[l]+val[x]); suf[x]=max(suf[x],sum[r]+val[x]); } int newnode(int v) { val[++tot]=sum[tot]=v; pre[tot]=suf[tot]=max(0,val[tot]); sum[tot]=val[tot]; siz[tot]=1; pri[tot]=rand(); return tot; } int build(int l,int r) { int top=0; int last,now; for(int i=l;i<=r;++i) { now=newnode(a[i]); last=0; while(top && pri[now]<pri[st[top]]) { update(st[top]); last=st[top--]; } if(top) ch[st[top]][1]=now; ch[now][0]=last; st[++top]=now; } while(top) update(st[top--]); return st[1]; } void down(int x) { int l=ch[x][0],r=ch[x][1]; if(tag[x]) { if(l) { val[l]=tag[x]; sum[l]=tag[x]*siz[l]; pre[l]=suf[l]=max(0,sum[l]); rev[l]=inv[l]=false; tag[l]=tag[x]; } if(r) { val[r]=tag[x]; sum[r]=tag[x]*siz[r]; pre[r]=suf[r]=max(0,sum[r]); rev[r]=inv[r]=false; tag[r]=tag[x]; } tag[x]=0; } if(rev[x]) { if(l) { swap(pre[l],suf[l]); swap(ch[l][0],ch[l][1]); rev[l]^=1; } if(r) { swap(pre[r],suf[r]); swap(ch[r][0],ch[r][1]); rev[r]^=1; } rev[x]^=1; } if(inv[x]) { if(l) { tmp=pre[l]; pre[l]=max(0,-(sum[l]-suf[l])); suf[l]=max(0,-(sum[l]-tmp)); sum[l]=pre[l]+min(0,-sum[l]-pre[l]); val[l]=-val[l]; inv[l]^=1; } if(r) { tmp=pre[r]; pre[r]=max(0,-(sum[r]-suf[r])); suf[r]=max(0,-(sum[r]-tmp)); sum[r]=pre[r]+min(0,-sum[r]-pre[r]); val[r]=-val[r]; inv[r]^=1; } inv[x]^=1; } } void split(int now,int k,int &x,int &y) { if(!now) x=y=0; else { down(now); if(k<=siz[ch[now][0]]) { y=now; split(ch[now][0],k,x,ch[now][0]); } else { x=now; split(ch[now][1],k-siz[ch[now][0]]-1,ch[now][1],y); } update(now); } } int merge(int x,int y) { if(x) down(x); if(y) down(y); if(!x || !y) return x+y; if(pri[x]<pri[y]) { ch[x][1]=merge(ch[x][1],y); update(x); return x; } else { ch[y][0]=merge(x,ch[y][0]); update(y); return y; } } int main() { int n,m; read(n); read(m); scanf("%s",ss+2); for(int i=2;i<=n+1;++i) if(ss[i]==')') a[i]=1; else a[i]=-1; root=build(1,n+2); int l,r; char s[10],cc[3]; int a,b,c,d,e; while(m--) { scanf("%s",s); read(l); read(r); l++; r++; split(root,r,a,b); split(a,l-1,c,d); if(s[0]=='R') { scanf("%s",cc); e= cc[0]==')' ? 1 : -1; tag[d]=e; val[d]=e; sum[d]=e*siz[d]; pre[d]=suf[d]=max(0,sum[d]); rev[d]=inv[d]=false; } else if(s[0]=='S') { rev[d]=true; swap(ch[d][0],ch[d][1]); swap(pre[d],suf[d]); } else if(s[0]=='I') { inv[d]=true; tmp=pre[d]; pre[d]=max(0,-(sum[d]-suf[d])); suf[d]=max(0,-(sum[d]-tmp)); sum[d]=pre[d]+min(0,-sum[d]-pre[d]); val[d]=-val[d]; } else printf("%d\n",(pre[d]+1)/2+(-sum[d]+pre[d]+1)/2); root=merge(merge(c,d),b); } }
2329: [HNOI2011]括号修复
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1229 Solved: 580
[Submit][Status][Discuss]