题意:给出一个一串括号字符串,和一系列操作。
有两种操作,1翻转某个括号2求只使用指定区间的括号,去掉匹配的括号后,第k个括号是什么。
首先建立一颗线段树,每个节点存储两个值rnum,lnum,代表仅使用这个区间的括号,去掉匹配的括号后剩下多少左括号右括号【因为肯定是)))(((类似的情况】。
线段树合并子节点操作是用左子树的左括号数和右子树的右括号数取min,得到本次合并匹配的括号数,从而得到父节点的左右括号数。
建好树后就可以知道第k个括号是什么了(或者超过数量,输出-1)。
根据节点合并操作的实现可以得知,如果我们从左向右访问线段树,那么’)’的数目是不会减少的;同理,从右向左访问时’(‘的数量不会减少。通过递归操作不断的确定第k小在左区间还是优区间缩小范围,直至叶子节点,即得出答案。
#include
#include
#include
using namespace std;
#define N 200010
char str[N];
struct Node
{
Node(int l=0,int r=0){lnum=l;rnum=r;}
int lnum,rnum;
}node[N<<2];
void pushup(int rt)
{
int matched=min(node[rt<<1].lnum,node[rt<<1|1].rnum);//×ó×ÓÊ÷µÄ×óÀ¨ºÅºÍÓÒ×ÓÊ÷µÄÓÒÀ¨ºÅÆ¥Åä
node[rt].lnum=node[rt<<1].lnum+node[rt<<1|1].lnum-matched;
node[rt].rnum=node[rt<<1].rnum+node[rt<<1|1].rnum-matched;
}
void build(int l,int r,int rt)
{
if(l==r)
{
node[rt].lnum=node[rt].rnum=0;
if(str[l]=='(')node[rt].lnum=1;
else node[rt].rnum=1;
return ;
}
int mid=(l+r)/2;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
Node query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return node[rt];
int mid=(l+r)/2;
Node ret;
if(L<=mid)ret=query(L,R,l,mid,rt<<1);
if(R>mid)
{
Node tmp=query(L,R,mid+1,r,rt<<1|1);
int matched=min(ret.lnum,tmp.rnum);
ret.lnum+=tmp.lnum-matched;
ret.rnum+=tmp.rnum-matched;
}
return ret;
}
void change(int x,int l,int r,int rt)
{
if(l==r&&r==x)
{
swap(node[rt].lnum,node[rt].rnum);
return;
}
int mid=(l+r)/2;
if(x<=mid)change(x,l,mid,rt<<1);
else change(x,mid+1,r,rt<<1|1);
pushup(rt);
return;
}
int lsearch(int L,int R,int K,Node &Val,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
int mid=(l+r)/2;
if(l==r)
{
int matched=min(Val.lnum,node[rt].rnum);
int lnum=Val.lnum+node[rt].lnum-matched;
int rnum=Val.rnum+node[rt].rnum-matched;
if(rnum==K)return l;
else
{
Val.lnum=lnum;
Val.rnum=rnum;
return 0;
}
}
int matched=min(Val.lnum,node[rt<<1].rnum);
int lnum=Val.lnum+node[rt<<1].lnum-matched;
int rnum=Val.rnum+node[rt<<1].rnum-matched;
if(K<=rnum)
{
return lsearch(L,R,K,Val,l,mid,rt<<1);
}
else
{
Val.lnum=lnum;
Val.rnum=rnum;
return lsearch(L,R,K,Val,mid+1,r,rt<<1|1);
}
}
int mid=(l+r)/2;
if(R<=mid)return lsearch(L,R,K,Val,l,mid,rt<<1);
if(L>mid)return lsearch(L,R,K,Val,mid+1,r,rt<<1|1);
int ret=lsearch(L,R,K,Val,l,mid,rt<<1);
if(ret)return ret;
else return lsearch(L,R,K,Val,mid+1,r,rt<<1|1);
}
int rsearch(int L,int R,int K,Node &Val,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
int mid=(l+r)/2;
if(l==r)
{
int matched=min(Val.rnum,node[rt].lnum);
int lnum=Val.lnum+node[rt].lnum-matched;
int rnum=Val.rnum+node[rt].rnum-matched;
if(lnum==K)return l;
else
{
Val.lnum=lnum;
Val.rnum=rnum;
return 0;
}
}
int matched=min(Val.rnum,node[rt<<1|1].lnum);
int lnum=Val.lnum+node[rt<<1|1].lnum-matched;
int rnum=Val.rnum+node[rt<<1|1].rnum-matched;
if(K<=lnum)
{
return rsearch(L,R,K,Val,mid+1,r,rt<<1|1);
}
else
{
Val.lnum=lnum;
Val.rnum=rnum;
return rsearch(L,R,K,Val,l,mid,rt<<1);
}
}
int mid=(l+r)/2;
if(R<=mid)return rsearch(L,R,K,Val,l,mid,rt<<1);
if(L>mid)return rsearch(L,R,K,Val,mid+1,r,rt<<1|1);
int ret=rsearch(L,R,K,Val,mid+1,r,rt<<1|1);
if(ret)return ret;
else return rsearch(L,R,K,Val,l,mid,rt<<1);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,q;
scanf("%d%d",&n,&q);
scanf(" %s",&str[1]);
int len=strlen(&str[1]);
//memset(node,0,sizeof(node));
build(1,len,1);
//printf("build ok\n");
for(int i=0;iint type;
scanf("%d",&type);
if(type==1)
{
int x;
scanf("%d",&x);
change(x,1,len,1);
}
else
{
int a,b,k;
scanf("%d%d%d",&a,&b,&k);
Node tp(0,0),qry=query(a,b,1,len,1);
//printf("query:left %d right %d\n",qry.lnum,qry.rnum);
int cnt=qry.lnum+qry.rnum;
if(cntprintf("-1\n");continue;}
if(k<=qry.rnum)
{
// printf("is a right Bracket\n");
printf("%d\n",lsearch(a,b,k,tp,1,len,1));
}
else
{
// printf("is a left Bracket\n");
printf("%d\n",rsearch(a,b,cnt-k+1,tp,1,len,1));
}
}
}
}
}