BZOJ 2329/2209 [HNOI2011]括号修复 (splay)
题目大意:
让你维护一个括号序列,支持
1.区间修改为同一种括号
2.区间内所有括号都反转
3.翻转整个区间,括号的方向不变
4.查询把某段区间变为合法的括号序列,至少需要修改多少次括号
给跪了,足足$de$了$3h$
感觉这道题的思维难度比维修数列高多了
前三个操作都非常好搞,都是区间打标记
注意下推标记的顺序,子树根如果有区间覆盖标记,那么子树内所有节点的反转和翻转标记都失效了,要清空
而下传到同一节点的区间覆盖和反转翻转标记不冲突
我们下推标记时必须保证,下推后,两个子节点的状态拿来就能用,不用再进行额外的修改
第四个操作,可以像维修数列那道题一样维护一个小$dp$,只不过这个$dp$更为复杂
定义$f[x][0/1][0/1]$表示节点$x$表示的子树,左/右边剩余的左/右括号数量
左边和右边表示的不是左右子树!
状态 左边右括号01 和 右边左括号10 表示x子树的括号序列,正匹配‘()’时,左边剩余的右括号和右边剩余的左括号一定不能被匹配,记录它们的数量
状态 左边左括号00 和 右边右括号11 表示x子树的括号序列,反匹配‘)(’时,左边剩余的左括号和右边剩余的右括号一定不能被匹配,记录它们的数量
转移就很显然了
void pushup(int x) { int ls=ch[x][0],rs=ch[x][1],w=val[x]?1:-1; f[x][0][0]=f[ls][0][0]+max(0,f[rs][0][0]-w-f[ls][1][1]); f[x][0][1]=f[ls][0][1]+max(0,f[rs][0][1]+w-f[ls][1][0]); f[x][1][0]=f[rs][1][0]+max(0,f[ls][1][0]-w-f[rs][0][1]); f[x][1][1]=f[rs][1][1]+max(0,f[ls][1][1]+w-f[rs][0][0]); sz[x]=sz[ls]+sz[rs]+1; }
而 覆盖/翻转/反转 操作同样需要修改dp,打表找规律可得
void Rpl(int x,int w) //覆盖 { memset(f[x],0,sizeof(f[x])); f[x][w^1][w]=f[x][w][w]=sz[x]; //不论反匹配还是正匹配,肯定全都不能被匹配上 val[x]=w, tag[x]=1, rev[x]=0, inv[x]=0; //去除反转翻转标记,否则可能会下传相反的覆盖标记 } void Rev(int x) //翻转,把序列翻转 { swap(f[x][0][0],f[x][1][0]); //反匹配变为正匹配,括号的位置改变,左右数量交换 swap(f[x][0][1],f[x][1][1]); swap(ch[x][0],ch[x][1]); rev[x]^=1; } void Inv(int x) //反转,左括号变右括号 { swap(f[x][0][0],f[x][0][1]); //反匹配变为正匹配,括号的位置不变,左右数量不变 swap(f[x][1][0],f[x][1][1]); val[x]^=1; inv[x]^=1; }
剩下就是常规的$splay$了
此外,一定要在$find$函数里下推标记,否则会找到错误的位置!
千万千万不要打错变量名,我有足足1h30min浪费在了打错的变量名上了..
1 #include <queue> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define N1 101000 7 #define M1 2010 8 #define S1 (N1<<1) 9 #define T1 (N1<<2) 10 #define ll long long 11 #define uint unsigned int 12 #define rint register int 13 #define dd double 14 #define il inline 15 #define inf 233333333 16 using namespace std; 17 18 int gint() 19 { 20 int ret=0,fh=1;char c=getchar(); 21 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 22 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 23 return ret*fh; 24 } 25 int n,m; 26 int a[N1]; 27 char str[N1]; 28 struct Splay{ 29 #define root ch[0][1] 30 int ch[N1][2],fa[N1],tag[N1],val[N1],rev[N1],inv[N1],sz[N1],f[N1][2][2]; 31 int idf(int x){return ch[fa[x]][0]==x?0:1;} 32 void Rpl(int x,int w) 33 { 34 memset(f[x],0,sizeof(f[x])); 35 f[x][w^1][w]=f[x][w][w]=sz[x]; 36 val[x]=w, tag[x]=1, rev[x]=0, inv[x]=0; 37 } 38 void Rev(int x) 39 { 40 swap(f[x][0][0],f[x][1][0]); 41 swap(f[x][0][1],f[x][1][1]); 42 swap(ch[x][0],ch[x][1]); rev[x]^=1; 43 } 44 void Inv(int x) //左括号变有括号。 45 { 46 swap(f[x][0][0],f[x][0][1]); 47 swap(f[x][1][0],f[x][1][1]); 48 val[x]^=1; inv[x]^=1; 49 } 50 void pushdown(int x) 51 { 52 int ls=ch[x][0],rs=ch[x][1]; 53 if(tag[x]) 54 { 55 if(ls) Rpl(ls,val[x]); 56 if(rs) Rpl(rs,val[x]); 57 inv[x]=rev[x]=tag[x]=0; return; 58 } 59 if(rev[x]) 60 { 61 if(ls) Rev(ls); 62 if(rs) Rev(rs); 63 rev[x]^=1; 64 } 65 if(inv[x]) 66 { 67 if(ls) Inv(ls); 68 if(rs) Inv(rs); 69 inv[x]^=1; 70 } 71 } 72 void pushup(int x) 73 { 74 int ls=ch[x][0],rs=ch[x][1],w=val[x]?1:-1; 75 f[x][0][0]=f[ls][0][0]+max(0,f[rs][0][0]-w-f[ls][1][1]); 76 f[x][0][1]=f[ls][0][1]+max(0,f[rs][0][1]+w-f[ls][1][0]); 77 f[x][1][0]=f[rs][1][0]+max(0,f[ls][1][0]-w-f[rs][0][1]); 78 f[x][1][1]=f[rs][1][1]+max(0,f[ls][1][1]+w-f[rs][0][0]); 79 sz[x]=sz[ls]+sz[rs]+1; 80 } 81 void rot(int x) 82 { 83 int y=fa[x],ff=fa[y],px=idf(x),py=idf(y); 84 fa[ch[x][px^1]]=y,ch[y][px]=ch[x][px^1]; 85 ch[x][px^1]=y,fa[y]=x,ch[ff][py]=x,fa[x]=ff; 86 pushup(y),pushup(x); 87 } 88 //int stk[N1],tp; 89 void splay(int x,int to) 90 { 91 int y=x; to=fa[to]; 92 while(fa[x]!=to) 93 { 94 y=fa[x]; 95 if(fa[y]==to) rot(x); 96 else if(idf(y)==idf(x)) rot(y),rot(x); 97 else rot(x),rot(x); 98 } 99 /*stk[++tp]=x; 100 while(fa[y]){stk[++tp]=fa[y],y=fa[y];} 101 while(tp){pushdown(stk[tp--]);}*/ 102 } 103 int build(int l,int r,int ff) 104 { 105 if(l>r) return 0; 106 int mid=(l+r)>>1,x=mid+1; 107 val[x]=a[mid];fa[x]=ff; 108 ch[x][0]=build(l,mid-1,x); 109 ch[x][1]=build(mid+1,r,x); 110 pushup(x); 111 return x; 112 } 113 int find(int K) 114 { 115 int x=root; 116 while(1) 117 { 118 pushdown(x); 119 if(K>sz[ch[x][0]]){ 120 K-=sz[ch[x][0]]; 121 if(K==1) {pushdown(x);return x;} 122 K--; x=ch[x][1]; 123 }else{ 124 x=ch[x][0]; 125 } 126 } 127 } 128 int split(int l,int r) 129 { 130 int x=find(l); splay(x,root); 131 int y=find(r+2); splay(y,ch[x][1]); 132 return ch[y][0]; 133 } 134 void Replace(int l,int r,int w) 135 { 136 int x=split(l,r); 137 val[x]=w; tag[x]=1; rev[x]=inv[x]=0; 138 memset(f[x],0,sizeof(f[x])); 139 f[x][w^1][w]=f[x][w][w]=sz[x]; 140 } 141 void Swp(int l,int r) 142 { 143 int x=split(l,r); 144 Rev(x); 145 } 146 void Invert(int l,int r) 147 { 148 int x=split(l,r), ls=ch[x][0], rs=ch[x][1]; 149 swap(f[x][0][0],f[x][0][1]), swap(f[x][1][0],f[x][1][1]); 150 val[x]^=1; inv[x]^=1; //val[ls]^=1; val[rs]^=1; 151 } 152 int Query(int l,int r) 153 { 154 int x=split(l,r); 155 return f[x][0][1]/2+((f[x][0][1]&1)?1:0)+f[x][1][0]/2+((f[x][1][0]&1)?1:0); 156 } 157 void debug() 158 { 159 for(int i=2;i<=n+1;i++) 160 printf("%c",val[i]?')':'('); 161 puts(""); 162 } 163 #undef root 164 }s; 165 166 int main() 167 { 168 //freopen("t2.in","r",stdin); 169 scanf("%d%d",&n,&m); 170 int i,j,x,y,w; 171 scanf("%s",str+1); 172 for(i=1;i<=n;i++) a[i]=(str[i]=='(')?0:1; 173 a[0]=0,a[n+1]=1; 174 s.ch[0][1]=s.build(0,n+1,0); 175 for(i=1;i<=m;i++) 176 { 177 scanf("%s",str); 178 if(str[0]=='R'){ 179 x=gint(), y=gint(), scanf("%s",str); 180 w=(str[0]=='(')?0:1; 181 s.Replace(x,y,w); 182 }else if(str[0]=='S'){ 183 x=gint(), y=gint(); 184 s.Swp(x,y); 185 }else if(str[0]=='I'){ 186 x=gint(), y=gint(); 187 s.Invert(x,y); 188 }else if(str[0]=='Q'){ 189 x=gint(), y=gint(); 190 printf("%d\n",s.Query(x,y)); 191 } 192 //s.debug(); 193 } 194 return 0; 195 }
附赠对拍程序以及数据生成器,建议自己写,考场上这种题不拍简直找死
暴力:
#include <queue> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #define N1 1010 #define M1 2010 #define S1 (N1<<1) #define T1 (N1<<2) #define ll long long #define uint unsigned int #define rint register int #define dd double #define il inline #define inf 233333333 using namespace std; int gint() { int ret=0,fh=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} return ret*fh; } int n,m; int a[N1],tmp[N1]; char str[N1]; void debug() { for(int i=1;i<=n;i++) printf("%c",a[i]?')':'('); puts(""); } int main() { freopen("t2.in","r",stdin); scanf("%d%d",&n,&m); int i,j,x,y,w; scanf("%s",str+1); for(i=1;i<=n;i++) a[i]=(str[i]=='(')?0:1; for(i=1;i<=m;i++) { scanf("%s",str); if(str[0]=='R'){ x=gint(), y=gint(), scanf("%s",str); w=(str[0]=='(')?0:1; for(j=x;j<=y;j++) a[j]=w; }else if(str[0]=='S'){ x=gint(), y=gint(); for(j=x;j<=y;j++) tmp[j-x+1]=a[j]; for(j=x;j<=y;j++) a[j]=tmp[y-j+1];//y-j+1 }else if(str[0]=='I'){ x=gint(), y=gint(); for(j=x;j<=y;j++) a[j]^=1; }else if(str[0]=='Q'){ x=gint(), y=gint(); int sum=0,ans=0,ret=0; for(j=x;j<=y;j++) { if(!a[j]) sum++; else if(sum>0) sum--; else ans++; } ret+=ans/2+((ans&1)?1:0); sum=ans=0; for(j=y;j>=x;j--) { if(a[j]) sum++; else if(sum>0) sum--; else ans++; } ret+=ans/2+((ans&1)?1:0); printf("%d\n",ret); } //debug(); } return 0; }
数据生成器:
#include <bits/stdc++.h> using namespace std; int main() { srand(time(NULL)); int n=20,m=20,i,x,l,r,t; printf("%d %d\n",n,m); for(i=1;i<=n;i++) x=rand()%2,printf("%c",(x&1)?')':'('); puts(""); for(i=1;i<=m;i++) { x=rand()%4; l=rand()%n+1; r=rand()%n+1; if(l>r) swap(l,r); if(x==0){ x=rand()%2; printf("Replace %d %d %c\n",l,r,(x&1)?')':'('); }else if(x==1){ printf("Swap %d %d\n",l,r); }else if(x==2){ printf("Invert %d %d\n",l,r); }else{ l=(rand()%(n/2))*2+1,r=(rand()%(n/2)+1)*2; if(l>r) swap(l,r); printf("Query %d %d\n",l,r); } } return 0; }