码迷,mamicode.com
首页 > 其他好文 > 详细

[HNOI2011][bzoj 2329] 括号修复 [splay+前缀和]

时间:2018-01-31 01:02:14      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:UI   using   cep   ted   freopen   更新   racket   turn   http   

题面:

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 }

 

[HNOI2011][bzoj 2329] 括号修复 [splay+前缀和]

标签:UI   using   cep   ted   freopen   更新   racket   turn   http   

原文地址:https://www.cnblogs.com/dedicatus545/p/8387569.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!