题解:
考试的时候连 O(nlog2n) O ( n l o g 2 n ) 的做法都没有想出来啊,太菜了……只询问第k位是哪种括号就很简单了,直接用线段树维护就好了,对于第k位在原来的位置,其实也可以搞,就在线段树上二分一下就好了,具体如何二分呢?对于每个区间,最后消完之后一定都是若干个(加上若干个)的形式,那么从左到右(的数量是单调不减的,)也同理,那么我们可以直接二分,做到 O(nlog2n) O ( n l o g 2 n ) ,对于 O(nlogn) O ( n l o g n ) 的做法,可以把询问包含的所有线段树的区间都拿出来,然后看具体是在哪个区间内,在哪个区间再二分,就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=500010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,a[Maxn];
char s[Maxn];
struct Seg{int lc,rc,l,r,c,ll,rr;}tr[Maxn<<1];
int tot=0;
void merge(Seg &x,Seg lc,Seg rc)
{
int t=min(lc.rr,rc.ll);
x.c=lc.c+rc.c-2*t;
int lll=lc.rr,rrr=rc.ll;
lll-=t,rrr-=t;
x.ll=lc.ll+rrr;
x.rr=rc.rr+lll;
}
void build(int l,int r)
{
int t=++tot;
tr[t].l=l;tr[t].r=r;
if(l==r)
{
tr[t].c=1;
if(a[l])tr[t].ll=1,tr[t].rr=0;
else tr[t].ll=0,tr[t].rr=1;
return;
}
int mid=l+r>>1;
tr[t].lc=tot+1,build(l,mid);
tr[t].rc=tot+1,build(mid+1,r);
merge(tr[t],tr[tr[t].lc],tr[tr[t].rc]);
}
void modify(int x,int p)
{
if(tr[x].l==tr[x].r)
{
tr[x].ll^=1,tr[x].rr^=1;
return;
}
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
if(p<=mid)modify(lc,p);
else modify(rc,p);
merge(tr[x],tr[lc],tr[rc]);
}
int pos[Maxn],lp;
void get(int x,int l,int r)
{
if(tr[x].l==l&&tr[x].r==r){pos[++lp]=x;return;}
int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
if(r<=mid)get(lc,l,r);
else if(l>mid)get(rc,l,r);
else get(lc,l,mid),get(rc,mid+1,r);
}
int query1(int x,int k)
{
if(tr[x].l==tr[x].r)return tr[x].l;
int lc=tr[x].lc,rc=tr[x].rc;
if(k<=tr[lc].ll)return query1(lc,k);
else return query1(rc,k-tr[lc].ll+tr[lc].rr);
}
int query2(int x,int k)
{
if(tr[x].l==tr[x].r)return tr[x].l;
int lc=tr[x].lc,rc=tr[x].rc;
if(k<=tr[rc].rr)return query2(rc,k);
else return query2(lc,k-tr[rc].rr+tr[rc].ll);
}
int main()
{
int T=read();
while(T--)
{
tot=0;
n=read(),m=read();
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
if(s[i]=='(')a[i]=0;
else a[i]=1;
}
build(1,n);
while(m--)
{
int op=read();
int l,r,x;
if(op==2)
{
l=read(),r=read(),x=read();
lp=0;
get(1,l,r);
Seg tmp=tr[pos[1]];
for(int i=2;i<=lp;i++)merge(tmp,tmp,tr[pos[i]]);
if(x>tmp.c){puts("-1");continue;}
if(x<=tmp.ll)
{
Seg t1,t2;
t1.ll=t1.rr=t1.c=0;t2=t1;
for(int i=1;i<=lp;i++)
{
merge(t1,t1,tr[pos[i]]);
if(t1.ll>=x)
{
printf("%d\n",query1(pos[i],x-t2.ll+t2.rr));
break;
}
t2=t1;
}
}
else
{
x=tmp.rr-(x-tmp.ll)+1;
Seg t1,t2;
t1.ll=t1.rr=t1.c=0;t2=t1;
for(int i=lp;i;i--)
{
merge(t1,tr[pos[i]],t1);
if(t1.rr>=x)
{
printf("%d\n",query2(pos[i],x-t2.rr+t2.ll));
break;
}
t2=t1;
}
}
}
else modify(1,read());
}
}
}