题意:先给出一个符合括号匹配的字符串,然后Q次操作
每次操作将某个括号反转,问将哪个括号反转能使字符串的括号再次匹配,位置要越靠近左端越好
假如(表示数字1,)表示数字-1,A[i]表示前i个括号代表的数字之和
((()))代表的数组A就是1 2 3 2 1 0
那么这些数字会有什么用呢,,我们可以来找下规律
如果是将(变成),如上面那个字符串的第2个反转,就会得到()())),对应的A数组是1 0 1 0 -1 -2
可以发现,反转后是以前的数组,在反转的位置t到n整个区间段的数字都减少了2
如果将)变成(,同理会得到,反转后在反转的位置到n整个区间段的数字都增加了2
所以我们可以得到一个这样的决策:
设反转的位置是t
若位置t是(,找到第一个),将)变成(,因为会使后面所有的数字都增加2,所以这样一定是最优的
若位置t是),找到一个位置p,使得[p+1,n]的所有数字都>=2,然后将p+1的括号反转,这样就会让后面的数字都减少2,就还原了
第一种情况可以用set维护,也可以利用F=A[i]-l的值去维护,如果[1,i]区间内存在),那么A[i]-l会小于0
第二种情况明显可以用线段树去维护最小值,然后通过最小值去定位
#include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<map> #include<set> #include<stack> #include<string> #include<iostream> #include<functional> #include<algorithm> using namespace std; typedef long long LL; typedef pair<LL, int> PLI; const int MX = 3e5 + 5; const int INF = 0x3f3f3f3f; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define root 1,n,1 char W[MX]; int MIN[MX << 2], F[MX << 2], col[MX << 2], A[MX]; void push_up(int rt) { MIN[rt] = min(MIN[rt << 1], MIN[rt << 1 | 1]); F[rt] = min(F[rt << 1], F[rt << 1 | 1]); } void push_down(int rt) { if(col[rt]) { col[rt << 1] += col[rt]; col[rt << 1 | 1] += col[rt]; MIN[rt << 1] += col[rt]; MIN[rt << 1 | 1] += col[rt]; F[rt << 1] += col[rt]; F[rt << 1 | 1] += col[rt]; col[rt] = 0; } } void build(int l, int r, int rt) { col[rt] = 0; if(l == r) { MIN[rt] = A[l]; F[rt] = A[l] - l; return; } int m = (l + r) >> 1; build(lson); build(rson); push_up(rt); } void update(int L, int R, int d, int l, int r, int rt) { if(L <= l && r <= R) { MIN[rt] += d; F[rt] += d; col[rt] += d; return; } int m = (l + r) >> 1; push_down(rt); if(L <= m) update(L, R, d, lson); if(R > m) update(L, R, d, rson); push_up(rt); } int query_1(int l, int r, int rt) { //查询第一个) if(l == r) { return l; } int m = (l + r) >> 1; push_down(rt); if(F[rt << 1] < 0) return query_1(lson); else return query_1(rson); } int query_2(int l, int r, int rt) {//查询一个位置,p,使[p+1,n]全部大于等于2 if(l == r) { return l; } int m = (l + r) >> 1; push_down(rt); if(MIN[rt << 1 | 1] < 2) return query_2(rson); else return query_2(lson); } int main() { //freopen("input.txt", "r", stdin); int n, Q, t, pos; while(~scanf("%d%d", &n, &Q)) { scanf("%s", W + 1); int sum = 0; for(int i = 1; i <= n; i++) { sum += W[i] == '(' ? 1 : -1; A[i] = sum; } build(root); while(Q--) { scanf("%d", &t); if(W[t] == '(') { W[t] = ')'; update(t, n, -2, root); t = query_1(root); W[t] = '('; update(t, n, 2, root); } else { W[t] = '('; update(t, n, 2, root); t = query_2(root) + 1; W[t] = ')'; update(t, n, -2, root); } printf("%d\n", t); } } }