题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2209
题意:给出一个括号序列,仅包含(和)。三种操作:(1)将[L,R]区间内的括号反转,即(变为),)变为(;(2)将[L,R]区间内的括号翻转,之前为a[L],a[L+1]……a[R-1],a[R],现在为a[R],a[R-1],……a[L+1],a[L];(3)询问[L,R]内至少需要修改多少个括号才能使得两两匹配?这里貌似可以认为这个询问的区间长度为偶数。
思路:对于一段括号,最后未匹配的必然是))))((((这种形式,或者是只剩下一种括号。假如现在知道最后未匹配的右括号为x个,左括号为y个,那么最少修改个数为:
即可以将右括号的前一半修改为左括号,左括号的后一半修改为右括号;若x和y为奇数,则各剩下一个,这两个剩下的均需要修改。为了比较容易维护,我们将左括号看做1,右括号看做-1,splay的每个节点保存LMin(左端连续最小和),LMax,RMin,RMax,这样剩余的右括号的个数显然就是-LMin,剩余的左括号的个数就是RMax,那么答案就是:
注意,这两种形式看起来是等价的,但是后一种才是真正正确的,即包含了所有情况。因为在这里我们会觉得在大多数时候LMin是个负数。但是有时候可能是正的,比如剩余括号序列为((((,此时LMin=1,RMax=4,答案为2,即将后两个修改为右括号。
struct node
{
int op1,op2,val,LMin,LMax,RMin,RMax,sum;
int size;
node *c[2],*p;
void flip()
{
val*=-1; sum*=-1;
int temp;
temp=LMin; LMin=-LMax; LMax=-temp;
temp=RMin; RMin=-RMax; RMax=-temp;
op1^=1;
}
void turnover()
{
swap(LMin,RMin);
swap(LMax,RMax);
swap(c[0],c[1]);
op2^=1;
}
};
node a[N],*root,*nullNode;
int cnt;
void pushUp(node *p)
{
if(p==nullNode) return;
p->size=1+p->c[0]->size+p->c[1]->size;
p->sum=p->c[0]->sum+p->val+p->c[1]->sum;
p->LMin=p->c[0]->LMin;
p->LMin=min(p->LMin,p->c[0]->sum+p->val);
p->LMin=min(p->LMin,p->c[0]->sum+p->val+p->c[1]->LMin);
p->LMax=p->c[0]->LMax;
p->LMax=max(p->LMax,p->c[0]->sum+p->val);
p->LMax=max(p->LMax,p->c[0]->sum+p->val+p->c[1]->LMax);
p->RMin=p->c[1]->RMin;
p->RMin=min(p->RMin,p->c[1]->sum+p->val);
p->RMin=min(p->RMin,p->c[1]->sum+p->val+p->c[0]->RMin);
p->RMax=p->c[1]->RMax;
p->RMax=max(p->RMax,p->c[1]->sum+p->val);
p->RMax=max(p->RMax,p->c[1]->sum+p->val+p->c[0]->RMax);
}
int ok(node *p)
{
return p!=nullNode&&(p!=&a[1])&&(p!=&a[2]);
}
void pushDown(node *p)
{
if(p==nullNode) return;
if(p->op1)
{
if(ok(p->c[0])) p->c[0]->flip();
if(ok(p->c[1])) p->c[1]->flip();
p->op1=0;
}
if(p->op2)
{
if(ok(p->c[0])) p->c[0]->turnover();
if(ok(p->c[1])) p->c[1]->turnover();
p->op2=0;
}
}
node *newNode(int val,node *p)
{
node *e=&a[cnt++];
e->c[0]=e->c[1]=nullNode;
e->p=p;
e->op1=e->op2=0;
e->size=1;
e->sum=e->val=e->LMin=e->RMin=e->LMax=e->RMax=val;
return e;
}
void init()
{
nullNode=0;
nullNode=newNode(0,nullNode);
nullNode->size=0;
nullNode->LMin=nullNode->RMin=INF;
nullNode->LMax=nullNode->RMax=-INF;
nullNode->sum=0;
root=newNode(0,nullNode);
root->LMin=root->RMin=INF;
root->LMax=root->RMax=-INF;
root->sum=0;
root->c[1]=newNode(0,root);
root->c[1]->LMin=root->c[1]->RMin=INF;
root->c[1]->LMax=root->c[1]->RMax=-INF;
root->c[1]->sum=0;
pushUp(root);
}
void zig(node *x)
{
node *p=x->p,*q=p->p;
p->c[0]=x->c[1];
if(x->c[1]!=nullNode) x->c[1]->p=p;
x->c[1]=p;
p->p=x;
x->p=q;
if(q!=nullNode)
{
if(q->c[0]==p) q->c[0]=x;
else q->c[1]=x;
}
pushUp(p);
pushUp(x);
if(root==p) root=x;
}
void zag(node *x)
{
node *p=x->p,*q=p->p;
p->c[1]=x->c[0];
if(x->c[0]!=nullNode) x->c[0]->p=p;
x->c[0]=p;
p->p=x;
x->p=q;
if(q!=nullNode)
{
if(q->c[0]==p) q->c[0]=x;
else q->c[1]=x;
}
pushUp(p);
pushUp(x);
if(root==p) root=x;
}
void splay(node *x,node *goal)
{
while(x->p!=goal)
{
if(x->p->p!=goal)
{
pushDown(x->p->p);
pushDown(x->p);
pushDown(x);
if(x->p->p->c[0]==x->p)
{
if(x->p->c[0]==x) zig(x->p),zig(x);
else zag(x),zig(x);
}
else
{
if(x->p->c[1]==x) zag(x->p),zag(x);
else zig(x),zag(x);
}
}
else
{
pushDown(x->p);
pushDown(x);
if(x->p->c[0]==x) zig(x);
else zag(x);
}
}
}
void select(int k,node *goal)
{
node *p=root;
pushDown(p);
while(k!=p->c[0]->size+1)
{
if(k<=p->c[0]->size) p=p->c[0];
else
{
k-=1+p->c[0]->size;
p=p->c[1];
}
pushDown(p);
}
splay(p,goal);
}
node *build(int L,int R,char str[],node *p)
{
if(L>R) return nullNode;
int mid=(L+R)>>1;
node *e=newNode(str[mid]=='('?1:-1,p);
e->c[0]=build(L,mid-1,str,e);
e->c[1]=build(mid+1,R,str,e);
pushUp(e);
return e;
}
void insert(int p,int n,char str[])
{
select(p+1,nullNode);
select(p+2,root);
node *e=build(1,n,str,root->c[1]);
root->c[1]->c[0]=e;
splay(e,nullNode);
}
int query(int L,int R)
{
select(L,nullNode);
select(R+2,root);
node *p=root->c[1]->c[0];
return -(p->LMin-1)/2+(p->RMax+1)/2;
}
void flip(int L,int R)
{
select(L,nullNode);
select(R+2,root);
node *p=root->c[1]->c[0];
p->flip();
splay(p,nullNode);
}
void turnover(int L,int R)
{
select(L,nullNode);
select(R+2,root);
node *p=root->c[1]->c[0];
p->turnover();
splay(p,nullNode);
}
int n,m;
char str[N];
int main()
{
init(); RD(n,m); RD(str+1); insert(0,n,str);
int op,x,y;
while(m--)
{
RD(op,x,y);
if(op==0) PR(query(x,y));
else if(op==1) flip(x,y);
else turnover(x,y);
}
}