1. 程式人生 > >BZOJ 2329/2209 [HNOI2011]括號修復 (splay)

BZOJ 2329/2209 [HNOI2011]括號修復 (splay)

括號序列 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,打表找規律可得

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;
}
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)