https://vjudge.net/contest/285175#problem/J
题目大意:给一个只包含
和
的字符串
,且保证它是平衡的(就是括号匹配的意思)。然后有
个询问,第
次询问把
进行翻转,让你求出最小的下标
,使得翻转
后,字符串
的括号依然是平衡的。
思路:假设
的值为
,
的值为
,那么我们就把字符串
变成了数的序列,用线段树维护这个序列的前缀和,以
为例,它每个位置的值分别为
。然后考虑翻转操作,若
,对其进行翻转,相当于把区间
的值都减去
,反之相当于把区间
的值都加上
;且对于第一个操作,我们找到第一个
进行翻转就可以了;对于第二个操作,我们需要从后往前找到最靠前的位置
,满足
。我们引入一个值
,若
,则说明
内至少有
个
,所以第一个操作的答案就是最靠前的位置
,满足
。区间修改、区间查询,用线段树就好了,详见代码。
由于上述操作的区间的特殊性,查询代码中对区间的修改也是很特殊的,看不懂的话不妨看一下函数调用,然后仔细思考一下。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
struct Tree
{
int l,r,m1,m2,lazy;
}tree[maxn<<2];
int n,q;
int a[maxn];
char s[maxn];
inline void up(int i)
{
tree[i].m1=min(tree[i<<1].m1,tree[i<<1|1].m1);
tree[i].m2=min(tree[i<<1].m2,tree[i<<1|1].m2);
}
inline void down(int i)
{
int l=i<<1,r=i<<1|1,v=tree[i].lazy;
tree[l].lazy+=v,tree[r].lazy+=v;
tree[l].m1+=v,tree[r].m1+=v;
tree[l].m2+=v,tree[r].m2+=v;
tree[i].lazy=0;
}
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r,tree[i].lazy=0;
if(l==r)
{
tree[i].m1=a[l]-l;
tree[i].m2=a[l];
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
up(i);
}
void update(int i,int l,int r,int v)
{
if(tree[i].l==l&&tree[i].r==r)
{
tree[i].m1+=v;
tree[i].m2+=v;
tree[i].lazy+=v;
return ;
}
if(tree[i].lazy)
down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)
update(i<<1,l,r,v);
else if(l>mid)
update(i<<1|1,l,r,v);
else
update(i<<1,l,mid,v),update(i<<1|1,mid+1,r,v);
up(i);
}
int query1(int i,int l,int r)//寻找[l,r]内 最靠左的 m1<0 的位置
{
if(l==r)
return l;
if(tree[i].lazy)
down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(tree[i<<1].m1<0)
return query1(i<<1,l,min(mid,r));
else
return query1(i<<1|1,mid+1,r);
}
int query2(int i,int l,int r)//查询[l,r]内最靠左的位置 pos 满足[pos,r]内的 m2 均>=2
{
if(l==r) //l+1 才是满足题意的位置哦~
return l+1;
if(tree[i].lazy)
down(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(tree[i<<1|1].m2>=2&&l<=mid)
return query2(i<<1,l,mid);
else
return query2(i<<1|1,mid+1,r);
}
int main()
{
scanf("%d%d",&n,&q);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
if(s[i]=='(')
a[i]=a[i-1]+1;
else
a[i]=a[i-1]-1;
}
build(1,1,n);
int qi,id;
while(q--)
{
scanf("%d",&qi);
if(s[qi]=='(')
{
s[qi]=')',update(1,qi,n,-2);
id=query1(1,1,qi);
s[id]='(',update(1,id,n,2);
}
else
{
s[qi]='(',update(1,qi,n,2);
id=query2(1,1,n);
s[id]=')',update(1,id,n,-2);
}
printf("%d\n",id);
}
return 0;
}