[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
原文地址:https://www.cnblogs.com/sto324/p/11298486.html