• bzoj 2209 [Jsoi2011]括号序列 平衡树


    2209: [Jsoi2011]括号序列

    Time Limit: 20 Sec  Memory Limit: 259 MB
    Submit: 1404  Solved: 699
    [Submit][Status][Discuss]

    Description

    Input

    输入数据的第一行包含两个整数N和Q,分别表示括号序列的长度,以及操作的个数。 第二行包含一个长度为N的括号序列。 接下来Q行,每行三个整数t、x和y,分别表示操作的类型、操作的开始位置和操作的结 束位置,输入数据保证x不小于y。其中t=0表示询问操作、t=1表示反转操作、t=2表示翻转操 作。

    Output

    对于每一个询问操作,输出一行,表示将括号序列的该子序列修改为配对,所需的最少改动 个数。

    Sample Input

    6 3
    )(())(
    0 1 6
    0 1 4
    0 3 4

    Sample Output

    2
    2
    0

    HINT

    100%的数据满足N,Q不超过10^5

    Source

    第一轮

    首先,对于一个括号序列,例如:())()(((,我们把可以匹配的去掉,就变成了:)(((。换句话说,对于一般的括号序列,化简以后就变成了左边x个")",右边y个"("。显然(x+y)为偶数,我们可以发现此时答案为x/2+y/2(x,y为偶数)或者x/2+1+y/2+1(x,y为奇数),合并一下就是[(x+1)/2]+[(y+1)/2]。

           关键是对于序列(l,r),x和y怎么求。实际上我们发现x就是求左端点为l,右端点<=r时,序列中右括号比左括号多的个数的最大值(>=0)。换句话说,如果令"("=1",("=-1,实际上x就是最小左子段和,y就是最大右子段和。由于还有反转(不是翻转)操作,因此还需要维护最大左子段和和最小右子段和。为了维护最小最大子段和,还需要维护一个区间和。
          然后就可以用splay的经典提取操作了。打两个标记就好了。
     
    因为在find的过程中已经翻转保证了当前根那部分是正确就可以了。
      1 #pragma GCC optimize(2)
      2 #pragma G++ optimize(2)
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<cmath>
      6 #include<cstdio>
      7 #include<cstring>
      8 
      9 #define N 100007
     10 using namespace std;
     11 inline int read()
     12 {
     13     int x=0,f=1;char ch=getchar();
     14     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
     15     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
     16     return x*f;
     17 }
     18 
     19 int n,m,rt;
     20 int c[N][2],sum[N],a[N],sz[N],fa[N];
     21 bool rev[N],ops[N];
     22 char ch[N];
     23 struct Node
     24 {
     25     int l0,l1,r0,r1;
     26     void LDI()
     27     {
     28         l0=-l0,l1=-l1;
     29         r0=-r0,r1=-r1;
     30     }
     31 }val[N];
     32 
     33 
     34 void update(int p)
     35 {
     36     int l=c[p][0],r=c[p][1];
     37     sum[p]=a[p]+sum[l]+sum[r],sz[p]=sz[l]+sz[r]+1;
     38     val[p].l0=min(val[l].l0,sum[l]+a[p]+val[r].l0);
     39     val[p].l1=max(val[l].l1,sum[l]+a[p]+val[r].l1);
     40     val[p].r0=min(val[r].r0,sum[r]+a[p]+val[l].r0);
     41     val[p].r1=max(val[r].r1,sum[r]+a[p]+val[l].r1);
     42 }
     43 void rotate(int x,int &k)
     44 {
     45     int y=fa[x],z=fa[y],l,r;
     46     if(c[y][0]==x)l=0;else l=1;r=l^1;
     47     if(y==k)k=x;
     48     else if(c[z][0]==y)c[z][0]=x;
     49     else c[z][1]=x;
     50     fa[x]=z,fa[y]=x,fa[c[x][r]]=y;
     51     c[y][l]=c[x][r],c[x][r]=y;
     52     update(y),update(x);
     53 }
     54 void splay(int x,int &k)
     55 {
     56     while(x!=k)
     57     {
     58         int y=fa[x],z=fa[y];
     59         if(y!=k)
     60         {
     61             if(c[y][0]==x^c[z][0]==y) rotate(x,k);
     62             else rotate(y,k);
     63         }
     64         rotate(x,k);
     65     }
     66 }
     67 void build(int &p,int l,int r,int par)
     68 {
     69     if(l>r){p=0;return;}
     70     p=(l+r)>>1;fa[p]=par;
     71     if(l==r)
     72     {
     73         sum[p]=a[l],sz[p]=1;
     74         if(a[l]<0) val[p].l0=val[p].r0=-1;
     75         else val[p].l1=val[p].r1=1;
     76         return;
     77     }
     78     build(c[p][0],l,p-1,p),build(c[p][1],p+1,r,p);
     79     update(p);
     80 }
     81 void rollback(int p)
     82 {
     83     ops[p]^=1,sum[p]=-sum[p],a[p]=-a[p];
     84     swap(val[p].l0,val[p].l1),swap(val[p].r0,val[p].r1);
     85     val[p].LDI();
     86 }
     87 void rever(int p)
     88 {
     89     rev[p]^=1;
     90     swap(val[p].l0,val[p].r0);
     91     swap(val[p].l1,val[p].r1);
     92 }
     93 void pushdown(int p)
     94 {
     95     if (rev[p])
     96     {
     97         swap(c[p][0],c[p][1]); rev[p]^=1;
     98         rever(c[p][0]),rever(c[p][1]);
     99     }
    100     if (ops[p])
    101     {
    102         rollback(c[p][0]),rollback(c[p][1]); ops[p]^=1;
    103     }
    104 }
    105 int find(int p,int x)
    106 {
    107     pushdown(p);
    108     int l=c[p][0],r=c[p][1];
    109     if(sz[l]+1==x)return p;
    110     else if(sz[l]>=x) return find(l,x);else return find(r,x-sz[l]-1);
    111 }
    112 int main()
    113 {
    114     n=read(),m=read();
    115     scanf("%s",ch+2);
    116     for (int i=2;i<=n+1;i++)
    117         if(ch[i]=='(')a[i]=1;else a[i]=-1;
    118     build(rt,1,n+2,0);
    119     while(m--)
    120     {
    121         int t=read(),l=read(),r=read();
    122         l=find(rt,l),r=find(rt,r+2);
    123         splay(l,rt),splay(r,c[rt][1]);
    124         int p=c[r][0];
    125         if(!t)printf("%d
    ",(val[p].r1+1)/2-(val[p].l0-1)/2);//左边取相反数.
    126         else if (t==1) rollback(p); else rever(p);
    127     }
    128 }
  • 相关阅读:
    食物
    连在一起的幻想乡
    【XSY3209】RGB Sequence
    【Luogu4389】付公主的背包
    【BZOJ4555】【TJOI2016】【HEOI2016】求和
    【BZOJ3456】城市规划
    【BZOJ2693】jzptab & 【BZOJ2154】Crash的数字表格
    【Learning】左偏树
    小Z的袜子
    【BZOJ3625】【CF438E】小朋友和二叉树
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8486672.html
Copyright © 2020-2023  润新知