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

 

posted @ 2018-12-21 21:02  guapisolo  阅读(156)  评论(0编辑  收藏  举报