[HNOI2011][bzoj 2329] 括号修复 [splay+前缀和]
题面:
http://www.lydsy.com/JudgeOnline/problem.php?id=2329
思路:
显然,操作4中输出补全的最小费用是关键
这决定了我们不可能在splay上只维护1-2个值。
考虑一段括号序列,将其中所有合法序列删去以后,留下的一定是形如 ))))))((( 的序列
因此首先考虑将每段区间左侧不匹配的括号数和右侧不匹配的括号数记录下来,分别为 left[l,r] 和 right[l,r]
此时除了Invert操作以外已经可以满足
但是对于Invert操作,对于每一个括号取反,显然每边只记录一个是不够的。
考虑再次转化模型,将括号序列抽象化成数字的和
发现:一个匹配的括号序列中左括号等于右括号,一段缩过的序列(去掉了所有的合法序列)的左侧右括号数量和右侧左括号数量,恰等于左右括号数量的前缀和以及后缀和。
因此,将右括号 )视为-1,左括号( 视为+1,对每一段区间,记录其最小前缀和和最大后缀和,即为上文所述 left && right
同时,我们记录区间的最大前缀和和最小后缀和,作为Swap和Invert操作时候用。
对于Swap操作,即为整个序列翻转,那么其最大前缀和与最大后缀和交换,最小前缀和与最小后缀和交换
对于Invert操作,需要交换最大最小前缀和,以及最大最小后缀和,再将它们全部取反
因为每个括号取反以后,原来最小的前缀和对应的哪一个序列,现在具有所有前缀里面的最大值(在相反数意义下)
后缀同理
统计答案即为对于所求区间,求 (l1/2)+(r2/2) ,若l1,r2是奇数,则还需加二(额外费用)
综上所述,令每一个)为-1,每一个(为1,记录每一个区间的最小最大前缀和 l1,l2 以及最小最大后缀和 r1,r2,将整个序列放到splay上操作即可。
需要注意的是,更新区间全部刷成同一个值的lazy标记时,一定要同时去掉已有的invert标记,以防WA
Code:
1 /************************************************************** 2 Problem: 2329 3 User: dedicatus545 4 Language: C++ 5 Result: Accepted 6 Time:10484 ms 7 Memory:6860 kb 8 ****************************************************************/ 9 10 #include<iostream> 11 #include<cstdio> 12 #include<cstring> 13 #include<algorithm> 14 using namespace std; 15 inline int read(){ 16 int re=0,flag=1;char ch=getchar(); 17 while(ch>'9'||ch<'0'){ 18 if(ch=='-') flag=-1; 19 ch=getchar(); 20 } 21 while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar(); 22 return re*flag; 23 } 24 int n,m,root,cnt; 25 int fa[100010],ch[100010][2],siz[100010]; 26 int w[100010],l1[100010],l2[100010],r1[100010],r2[100010],sum[100010]; 27 int rev[100010]={0},lazy[100010]={0},inv[100010]={0}; 28 int x[100010]; 29 //lazy==1: ( 30 //lazy==-1: ) 31 void _swap(int &x,int &y){x^=y;y^=x;x^=y;} 32 int _max(int x,int y){return (x<y)?y:x;} 33 int _min(int x,int y){return (x>y)?y:x;} 34 void update(int x){ 35 if(!x) return; 36 sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+w[x]; 37 siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1; 38 l1[x]=_min(l1[ch[x][0]],sum[ch[x][0]]+w[x]+l1[ch[x][1]]); 39 l2[x]=_max(l2[ch[x][0]],sum[ch[x][0]]+w[x]+l2[ch[x][1]]); 40 r1[x]=_min(r1[ch[x][1]],sum[ch[x][1]]+w[x]+r1[ch[x][0]]); 41 r2[x]=_max(r2[ch[x][1]],sum[ch[x][1]]+w[x]+r2[ch[x][0]]); 42 } 43 void pushdown(int x,int t){ 44 if(!x) return; 45 inv[x]=0;w[x]=t;lazy[x]=t; 46 if(~t){ 47 sum[x]=siz[x]; 48 l1[x]=r1[x]=0; 49 l2[x]=r2[x]=sum[x]; 50 } 51 else{ 52 sum[x]=~siz[x]+1; 53 l2[x]=r2[x]=0; 54 l1[x]=r1[x]=sum[x]; 55 } 56 } 57 void pushrev(int x){ 58 if(!x) return; 59 _swap(ch[x][0],ch[x][1]); 60 _swap(l1[x],r1[x]); 61 _swap(l2[x],r2[x]); 62 rev[x]^=1; 63 } 64 void pushinv(int x){ 65 if(!x) return; 66 _swap(l1[x],l2[x]); 67 _swap(r1[x],r2[x]); 68 l1[x]=~l1[x]+1;l2[x]=~l2[x]+1; 69 r1[x]=~r1[x]+1;r2[x]=~r2[x]+1; 70 w[x]=~w[x]+1;sum[x]=~sum[x]+1;inv[x]^=1; 71 } 72 void push(int x){ 73 if(!x) return; 74 if(rev[x]){ 75 pushrev(ch[x][0]); 76 pushrev(ch[x][1]); 77 rev[x]=0; 78 } 79 if(lazy[x]){ 80 pushdown(ch[x][0],lazy[x]); 81 pushdown(ch[x][1],lazy[x]); 82 lazy[x]=0; 83 } 84 if(inv[x]){ 85 pushinv(ch[x][0]); 86 pushinv(ch[x][1]); 87 inv[x]=0; 88 } 89 } 90 int get(int x){return ch[fa[x]][1]==x;} 91 void rotate(int x){ 92 int f=fa[x],ff=fa[f],son=get(x); 93 push(f);push(x); 94 ch[f][son]=ch[x][son^1]; 95 if(ch[f][son]) fa[ch[f][son]]=f; 96 fa[f]=x;ch[x][son^1]=f; 97 fa[x]=ff; 98 if(ff) ch[ff][ch[ff][1]==f]=x; 99 update(f);update(x); 100 } 101 void splay(int x,int to){ 102 if(x==to||fa[x]==to) return; 103 if(!to) root=x; 104 for(int f;(f=fa[x])&&f!=to;rotate(x)) 105 if(fa[f]!=to) 106 rotate(get(f)==get(x)?f:x); 107 update(x); 108 } 109 int rank(int x,int pos){ 110 push(pos); 111 if(siz[ch[pos][0]]+1==x){ 112 splay(pos,0);return pos; 113 } 114 if(siz[ch[pos][0]]>=x) return rank(x,ch[pos][0]); 115 else return rank(x-siz[ch[pos][0]]-1,ch[pos][1]); 116 } 117 int build(int le,int ri,int f){ 118 if(le>ri) return 0; 119 int mid=(le+ri)>>1,cur=++cnt; 120 //cout<<"build "<<le<<" "<<ri<<" "<<mid<<" "<<x[mid]<<"\n"; 121 w[cur]=x[mid];fa[cur]=f; 122 ch[cur][0]=build(le,mid-1,cur); 123 ch[cur][1]=build(mid+1,ri,cur); 124 update(cur);return cur; 125 } 126 void change(int le,int ri,int t){ 127 int x=rank(le,root),y=rank(ri+2,root); 128 splay(x,0);splay(y,root); 129 pushdown(ch[y][0],t); 130 update(y);update(x); 131 } 132 void reverse(int le,int ri){ 133 int x=rank(le,root),y=rank(ri+2,root); 134 splay(x,0);splay(y,root); 135 pushrev(ch[y][0]); 136 update(y);update(x); 137 } 138 void invert(int le,int ri){ 139 int x=rank(le,root),y=rank(ri+2,root); 140 splay(x,0);splay(y,root); 141 pushinv(ch[y][0]); 142 update(y);update(x); 143 } 144 int query(int le,int ri){ 145 int x=rank(le,root),y=rank(ri+2,root); 146 splay(x,0);splay(y,root); 147 return ((r2[ch[y][0]]+1)>>1)-((l1[ch[y][0]]-1)/2); 148 } 149 void dfs(int u){ 150 if(!u) return; 151 push(u); 152 dfs(ch[u][0]); 153 printf("%d %d %d %d\n",u,fa[u],ch[u][0],ch[u][1]); 154 printf("%d %d %d %d %d\n",w[u],l1[u],l2[u],r1[u],r2[u]); 155 dfs(ch[u][1]); 156 } 157 char s[100010]; 158 int main(){ 159 // freopen("brackets.in","r",stdin); 160 // freopen("brackets.out","w",stdout); 161 int i,t1,t2,t4;char t3; 162 n=read();m=read(); 163 scanf("%s",s); 164 for(i=1;i<=n;i++) x[i]=((s[i-1]=='(')?1:-1); 165 root=build(0,n+1,0); 166 //dfs(root);printf("\n"); 167 for(i=1;i<=m;i++){ 168 scanf("%s",s); 169 if(s[0]=='R'){ 170 t1=read();t2=read();t3=getchar(); 171 while(t3!='('&&t3!=')') t3=getchar(); 172 t4=((t3=='(')?1:-1); 173 change(t1,t2,t4); 174 } 175 if(s[0]=='I'){ 176 t1=read();t2=read(); 177 invert(t1,t2); 178 } 179 if(s[0]=='Q'){ 180 t1=read();t2=read(); 181 printf("%d\n",query(t1,t2)); 182 } 183 if(s[0]=='S'){ 184 t1=read();t2=read(); 185 reverse(t1,t2); 186 } 187 //dfs(root);printf("\n"); 188 } 189 }