zoukankan      html  css  js  c++  java
  • [HNOI2011]括号修复 / [JSOI2011]括号序列

    题意

    给出一个括号序列,有四种操作:

    1.将[l,r]的区间的括号都变成c

    2.将[l,r]的区间括号序列翻转

    3.将[l,r]的区间的括号取反

    4.询问[l,r]区间至少需要翻转几个括号才能合法

    100%的数据满足N,M≤100000N,M100000。

    输入数据保证问题有解。

    题解

    对于一串不合法的括号序列我们可以先去掉配对的括号,那么他就变成'))(((('这样的形式,左边是一串')',右边是一串'(',记')'的个数x,'('的个数y,x与y同奇偶(加起来是偶数),当是偶数时,他们各自可以进行内部改变,ans=x/2+y/2;当时奇数时,两边各剩下一个,他们都改变,ans=x/2+y/2+2;(都是下取整)

    那么总结起来就是ans=(x+1)/2+(y+1)/2。(下取整)

    那怎么去统计这个信息呢,应该是一种套路(我猜的):把')'看做1,'('看做-1,那么最大前缀就是x,最小后缀就是-y。求最大前缀和最小后缀的方法和求最大子段和里面那个一样。

    然后就可以做了,第一个操作维护覆盖标记cover;

    第二个操作维护翻转标记res,因为要交换左右的最大最小值,左右需要四个值lmax,lmin,rmax,rmin,记得交换(lmax,rmax),(lmin,rmin)。

    第三个操作就相当于是区间乘以-1,这都是老套路了,在lmax,lmin,rmax,rmin都乘以-1之后,交换(lmin,lmax),(rmin,rmax)。

    最后一个操作找到区间输出(lmax+1)/2+(-rmin+1)/2即可

    要注意的就是标记下放,还是覆盖标记先,并且下放覆盖标记时,还要清掉下放目标的其他两个标记。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100005;
    const int oo=100000;
    int n,m,root,num;
    int a[maxn];
    char s[maxn],op[15];
    struct Splay{
      int fa,s[2],size,res,tag,cover;
      int val,lmax,lmin,rmax,rmin,sum;
    }tr[maxn];
    
    template<class T>inline void read(T &x){
      x=0;int f=0;char ch=getchar();
      while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
      while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
      x= f ? -x : x ;
    }
    
    int max(int x,int y){return x>y ? x : y ;}
    int min(int x,int y){return x<y ? x : y ;}
    void swap(int &x,int &y){int t=x;x=y;y=t;}
    
    void update(Splay &ret,Splay lx,Splay ry){
      ret.size=lx.size+ry.size+1;
      ret.sum=lx.sum+ret.val+ry.sum;
      ret.lmax=max(lx.lmax,lx.sum+ret.val+ry.lmax);
      ret.rmax=max(ry.rmax,ry.sum+ret.val+lx.rmax);
      ret.lmin=min(lx.lmin,lx.sum+ret.val+ry.lmin);
      ret.rmin=min(ry.rmin,ry.sum+ret.val+lx.rmin);
    }
    
    void update(int now){
      update(tr[now],tr[tr[now].s[0]],tr[tr[now].s[1]]);
    }
    
    int build(int l,int r,int f){
      if(l>r) return 0;
      int now=++num,mid=(l+r)>>1;
      tr[now].fa=f;
      tr[now].val=a[mid];
      tr[now].cover=oo;
      if(l==r){
        tr[now].lmax=tr[now].rmax=max(0,tr[now].val);
        tr[now].lmin=tr[now].rmin=min(0,tr[now].val);
        tr[now].sum=tr[now].val;
        tr[now].size=1;
        return now;
      }
      tr[now].s[0]=build(l,mid-1,now);
      tr[now].s[1]=build(mid+1,r,now);
      update(now);
      return now;
    }
    
    
    void put_cover(int x,int val){
      tr[x].res=tr[x].tag=0;
      tr[x].cover=tr[x].val=val;
      tr[x].sum=val*tr[x].size;
      tr[x].lmax=tr[x].rmax=max(0,tr[x].sum);
      tr[x].lmin=tr[x].rmin=min(0,tr[x].sum);
    }
    
    void put_res(int x){
      if(!x) return ;
      tr[x].res^=1;
      swap(tr[x].s[0],tr[x].s[1]);
      swap(tr[x].lmax,tr[x].rmax);
      swap(tr[x].lmin,tr[x].rmin);
    }
    
    void put_tag(int x){
      if(!x) return ;
      tr[x].tag^=1;
      tr[x].val*=-1;
      tr[x].sum*=-1;
      tr[x].lmax*=-1;
      tr[x].lmin*=-1;
      tr[x].rmax*=-1;
      tr[x].rmin*=-1;
      swap(tr[x].lmax,tr[x].lmin);
      swap(tr[x].rmax,tr[x].rmin);
    }
    
    void push_down(int x){
      if(tr[x].cover!=oo){
        put_cover(tr[x].s[0],tr[x].cover);
        put_cover(tr[x].s[1],tr[x].cover);
        tr[x].cover=oo;
      }
      if(tr[x].res){
        put_res(tr[x].s[0]);
        put_res(tr[x].s[1]);
        tr[x].res=0;
      }
      if(tr[x].tag){
        put_tag(tr[x].s[0]);
        put_tag(tr[x].s[1]);
        tr[x].tag=0;
      }
    }
    
    void debug(int x){
      push_down(x);
      if(tr[x].s[0]) debug(tr[x].s[0]);
      printf("%d ",tr[x].val);
      if(tr[x].s[1]) debug(tr[x].s[1]);
    }
    
    int find(int k){
      int now=root;
      while(1){
        push_down(now);
        if(tr[tr[now].s[0]].size>=k) {now=tr[now].s[0];continue;}
        k-=tr[tr[now].s[0]].size;
        if(k==1) return now;
        k--;
        now=tr[now].s[1];
      }
    }
    
    int get(int x){
      return tr[tr[x].fa].s[1]==x;
    }
    
    void connect(int x,int y,int d){
      tr[y].s[d]=x;
      tr[x].fa=y;
    }
    
    void rotate(int x){
      int f=tr[x].fa,ff=tr[f].fa;
      int d1=get(x),d2=get(f);
      int cs=tr[x].s[d1^1];
      connect(x,ff,d2);
      connect(f,x,d1^1);
      connect(cs,f,d1);
      update(f);
      update(x);
    }
    
    void splay(int x,int go){
      if(go==root) root=x;
      go=tr[go].fa;
      while(tr[x].fa!=go){
        int f=tr[x].fa;
        if(tr[f].fa==go) rotate(x);
        else if(get(x)==get(f)) {rotate(f);rotate(x);}
        else {rotate(x);rotate(x);}
      }
    }
    
    void replace(){
      int l,r;
      read(l);read(r);scanf("%s",op);
      int x=find(l),y=find(r+2);
      splay(x,root);
      splay(y,tr[x].s[1]);
      //printf("%d %d
    ",x,y);
      put_cover(tr[y].s[0],op[0]==')' ? 1 : -1);
      //putchar(10);
      //debug(root);
      //putchar(10);
      update(y);
      update(x);
    }
    
    void reverse(){
      int l,r;
      read(l);read(r);
      int x=find(l),y=find(r+2);
      splay(x,root);
      splay(y,tr[x].s[1]);
      put_res(tr[y].s[0]);
      update(y);
      update(x);
    }
    
    void invert(){
      int l,r;
      read(l);read(r);
      int x=find(l),y=find(r+2);
      splay(x,root);
      splay(y,tr[x].s[1]);
      put_tag(tr[y].s[0]);
      update(y);
      update(x);
    }
    
    int query(){
      int l,r;
      read(l);read(r);
      int x=find(l),y=find(r+2);
      splay(x,root);
      splay(y,tr[x].s[1]);
      int pos=tr[y].s[0];
      //printf("
    %d %d
    ",tr[pos].lmax,tr[pos].rmin);
      return ((tr[pos].lmax+1)>>1)+((-tr[pos].rmin+1)>>1);
    }
    
    int main(){
      read(n);read(m);
      a[1]=-oo;a[n+2]=oo;
      scanf("%s",s+2);;
      for(int i=2;i<=n+1;i++)
       a[i]= s[i]==')' ? 1 : -1;
      root=build(1,n+2,0);
      for(int i=1;i<=m;i++){
        scanf("%s",op);
        if(op[0]=='R') replace();
        else if(op[0]=='S') reverse();
        else if(op[0]=='I') invert();
        else printf("%d
    ",query());
        //putchar(10);
        //debug(root);
        //putchar(10);
      }
    }
    View Code
  • 相关阅读:
    grub.conf文件说明
    grub手动引导win7
    手动grub引导redhat
    grub的三种安装方式
    试题系列五(公鸡5元一只,母鸡3元一只,小鸡1元3只,求100元刚好买100只鸡的可能)
    试题系列四(袋中有6红球 3黄球 3绿球,从中取6个球,求所有拿到球的颜色的可能 c(12,6))
    试题系列三(求任意两个数的最大公约数)
    试题系列二(求1000内的完数)
    试题系列一(求4,5,6,7所有四位数的排列组合)
    pthread_cleanup_push和pthread_cleanup_pop清除函数是否执行的说明
  • 原文地址:https://www.cnblogs.com/sto324/p/11298486.html
Copyright © 2011-2022 走看看