BZOJ 2329/2209 [HNOI2011]括號修復 (splay)
阿新 • • 發佈:2018-12-22
括號序列 inline lin space 所有 define getchar int 維修
題目大意:
讓你維護一個括號序列,支持
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,打表找規律可得
voidRpl(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; }View Code
數據生成器:
#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; }View Code
BZOJ 2329/2209 [HNOI2011]括號修復 (splay)