要想使括号匹配,sum数组的值要都大于0
//struct A
//{
// int x,y;
// bool operator < (const A & a) const
// {
// return x>a.x;
// }
//}; //优先队列(按结构体中的x从小到大排序)
//priority_queue <A> q;
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
#define eps 0.0000000001
#define read(a) scanf("%d",&a)
#define mem(a) memset(a,0,sizeof(a))
#define maxx 1e10
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
//priority_queue<int,vector<int>,greater<int> > q;
#define mod 1000000007
const int maxn=300100;
set<int> st;
char cs[maxn];
int a[maxn];
int sum[maxn*4];
int Add[maxn*4];//懒惰标记
void PushUp(int n)
{
sum[n]=min(sum[n*2],sum[n*2+1]);
return;
}
//建树
void Build(int l,int r,int num)
{
if(l==r)
{
sum[num]=a[l];
return;
}
int m=(l+r)/2;
//左右递归
Build(l,m,num*2);
Build(m+1,r,num*2+1);
//该结点值等于左右孩子结点值的和
PushUp(num);
return;
}
//点更新 假设a[x]+=s;
void Update1(int x,int s,int l,int r,int num)
{
if(l==r)
{
sum[num]+=s;
return;
}
int m=(l+r)/2;
//根据m和x的位置关系判断调用左子树还是右子树
if(x<=m)//左
Update1(x,s,l,m,num*2);
else
Update1(x,s,m+1,r,num*2+1);
PushUp(num);
}
// 下推标记函数
void PushDown(int num,int ln,int rn)//ln和rn是左子树和右子树的数量
{
if(Add[num]) //如果被标记了
{
Add[num*2]+=Add[num];
Add[num*2+1]+=Add[num];// 把标记推到左右子树
//修改子节点的Sum使之与对应的Add相对应
sum[num*2]+=Add[num];
sum[num*2+1]+=Add[num];
Add[num]=0;
}
return;
}
//区间更新 假设L到R 加C
void Update2(int L,int R,int C,int l,int r,int num)
{
if(l>=L&&R>=r)
{
sum[num]+=C;
Add[num]+=C;//增加Add标记,表示本区间的Sum正确,子区间的Sum仍需要根据Add的值来调整
return;
}
int m=(l+r)/2;
PushDown(num,m-l+1,r-m); //下推标记
if(L<=m)
Update2(L,R,C,l,m,num*2);
if(R>=m+1)
Update2(L,R,C,m+1,r,num*2+1);
PushUp(num);
return;
}
//区间查询 查询区间 L-R
int Query(int L,int R,int l,int r,int num)
{
if(L<=l&&R>=r) //l,r在L,R内
{
return sum[num];
}
int m=(l+r)/2;
PushDown(num,m-l+1,r-m);
int ans=inf;
if(L<=m)
ans=min(ans,Query(L,R,l,m,num*2));
if(R>=m+1)
ans=min(ans,Query(L,R,m+1,r,num*2+1));
return ans;
}
int erfen(int x,int n,int mini)
{
int l=1,r=x-1,m,ans=x;
while(l<=r) //二分
{
m=(l+r)/2;
if(Query(m,x-1,1,n,1)>=mini) //找到最小值大于2的区间
{//如果右区间最小值大于等于mini,就把右端点向左缩
ans=m;
r=m-1;
}
else//否则,就把左端点舍掉
l=m+1;
}
return ans;
}
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
scanf("%s",cs+1);
a[1]=0;
st.clear();
for(int i=1;i<=n;i++)
{
if(cs[i]=='(')
a[i]=a[i-1]+1;
else
{
a[i]=a[i-1]-1;
st.insert(i);
}
}
// for(int i=1;i<=n;i++)
// cout<<a[i]<<" ";
mem(Add);
Build(1,n,1);
int x,ans;
for(int i=0;i<m;i++)
{
read(x); //x是反转的位置
if(cs[x]==')')
{
ans=erfen(x,n,2);
if(ans<x)
{
Update2(ans,x-1,-2,1,n,1);//sum数组中x后面的的值已经被两次翻转抵消了
cs[x]='(';cs[ans]=')'; //所以只需要把ans和x中间的部分减掉就好
st.insert(ans);
st.erase(x);
}
//else的情况就是在原位置再反转回来
// ans==x
}
else//上一个是因为要减2,要保证sum数组的值不为0,所以不能减小于2的部分
{//因为我需要把右括号翻转成左括号,sum数组的值要加2,所以没有限制条件
//直接找到第一个翻转就好
ans=*st.begin();
if(ans>x)
ans=x;
if(ans<x)
{
Update2(ans,x-1,2,1,n,1); //同上一个更新
cs[x]=')';cs[ans]='(';
st.insert(x);
st.erase(ans);
}
}
cout<<ans<<endl;
}
}
return 0;
}