题意:先给出一个符合括号匹配的字符串,然后Q次操作
每次操作将某个括号反转,问将哪个括号反转能使字符串的括号再次匹配,位置要取最左端符合条件的。
可以利用前缀和 比如(())那么前缀和分别就是1,2,1,0。观察到,平衡时前缀和都是等于0的。
通过前缀和,我们可以发现规律:
将一个'('翻转成')'会使得从当前位置开始到字符串最后的前缀和都会减2
如果将')'翻转成'(',同理,此位置开始以后的所有前缀和都要加2
而如果减去了2,那如何增加2抵消掉之前的影响,得到最后的后缀和为零
而减去2的话肯定是'('翻转成')',那么如何加一个数抵消掉')'的影响
如果是将p点翻转的话,肯定是从[1,p],找一个')',将')'翻转成'('
有没有发现规律,如果是'('翻转成')',则是在之前的区间将')'翻转成'(',那么将')'翻转成'('时,就是往后,找一个'('将其'('翻转成')'
维护该区间的最小值即可,只要最小值不小于2,那么该区间的所有值都不会小于2
提供一个朋友的详解地址,说的很好:http://blog.csdn.net/qwb492859377/article/details/47357553
/*
Author: 2486
Memory: 32700 KB Time: 760 MS
Language: C++ Result: Accepted
VJ RunId: 4340427 Real RunId: 149963
*/
#include
#include
#include
#include
#include
using namespace std;
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define root 1, 1, n
const int MAXN = 5e5 + 5;
const int INF = 0x3f3f3f3f;
int sum[MAXN << 2];
int Min[MAXN << 2],col[MAXN << 2],val[MAXN << 2];
int S,n,m;
char str[MAXN];
void pushup_1(int rt) {
sum[rt] = min(sum[rt << 1], sum[rt << 1|1]);
}
void build(int rt, int l, int r) {
col[rt] = 0;
if(l == r) {
val[rt] = (str[l] == '(' ? 1 : -1);
S += val[rt];
Min[rt] = S;
sum[rt] = val[rt] == 1 ? INF : l;
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
pushup_1(rt);
Min[rt] = min(Min[rt << 1], Min[rt << 1|1]);
}
int update_1(int p, int rt, int l, int r) {
if(l == r) {
int tmp = val[rt];
val[rt] *= -1;
sum[rt] = tmp == 1 ? p : INF;
return tmp;
}
int mid = (l + r) >> 1, ret;
if(p <= mid) ret = update_1(p, lson);
if(p > mid) ret = update_1(p, rson);
pushup_1(rt);
return ret;
}
void pushdown(int rt) {
if(col[rt]) {
col[rt << 1] += col[rt];
col[rt << 1|1] += col[rt];
col[rt] = 0;
}
}
void pushup_2(int rt) {
Min[rt] = min(Min[rt << 1] + col[rt << 1], Min[rt << 1|1] + col[rt << 1|1]);
}
void update_2(int L, int R, int c,int rt, int l, int r) {
if(L <= l && r <= R) {
col[rt] += c;
return;
}
pushdown(rt);
int mid = (l + r) >> 1;
if(L <= mid) update_2(L, R, c, lson);
if(R > mid) update_2(L, R, c, rson);
pushup_2(rt);
}
int query(int rt, int l,int r) {
if(Min[rt] + col[rt] >= 2) return l;
if(l == r) return r + 1;
pushdown(rt);
int mid = (l + r) >> 1;
int ret;
if(Min[rt << 1|1] + col[rt << 1|1] >= 2) ret = query(lson);
else ret = query(rson);
pushup_2(rt);
return ret;
}
int main() {
int p;
while(~scanf("%d %d",&n,&m)) {
scanf("%s",str+1);
S = 0;
build(root);
while(m--) {
scanf("%d",&p);
int tmp = update_1(p, root);
update_2(p, n, tmp * (-2), root);
printf("%d\n",p = (tmp == 1 ? sum[1] : query(root)));
update_1(p, root);
update_2(p, n, tmp * 2, root);
}
}
return 0;
}