题目大意:给定一个合法的括号序列(只包含'(',')'),有q次操作,对每次操作改变一个位置的括号,求最左端的位置,使得改变这个位置上的括号以后,新序列合法(完全配对)。
思路:对于合法的括号序列,如果把括号序列一次进行栈操作,把'('进栈,')'则把最近的'('出栈,令a[i]表示到i位置后栈里面的左括号个数,也就是i位置的左括号数目和右括号数目的差。则原序列对应新的数组a。原序列合法 等价于 对于1<=i<=n,a[i]>=0 恒成立。那么对于把位置pos上的括号改变一下,如果是'(' - ')',那么a[pos~n]会都减去2,如果是')'->'(',那么a[pos~n]会都加上2。分类讨论后,答案不难得出。对于'('->')'答案就是从左至右找第一个右括号;对于')'->'(',答案就是找一个最左端的位置pos0,使得a[pos0~pos-1]都大于等于2。对于找第一个右括号,可以转化为用新的数组b[i] = a[i] - i,找第一个小于0的位置,进而转化为找最大的前缀区间使得这个区间上的b的最小值等于0。对于找最左端的位置,也可以转化为区间最值来做,详见代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <map> 6 #include <queue> 7 #include <cmath> 8 #include <vector> 9 #include <ctime> 10 #define mem0(a) memset(a, 0, sizeof(a)) 11 #define lson l, m, rt << 1 12 #define rson m + 1, r, rt << 1 | 1 13 #define define_m int m = (l + r) >> 1 14 #define LL long long 15 #define Rep(a, b) for(int a = 0; a < b; a++) 16 #define lowbit(x) ((x) & (-(x))) 17 const int dx[4] = {1, 0, -1, 0}; 18 const int dy[4] = {0, -1, 0, 1}; 19 const int INF = 1e9 + 7; 20 const int maxn = 300010; 21 const double eps = 1e-13; 22 typedef double db; 23 using namespace std; 24 struct SegTree { 25 struct Node { 26 int minv, add; 27 } tree[maxn << 2]; 28 void PushUp(int rt) { 29 tree[rt].minv = min(tree[rt << 1].minv, tree[rt << 1 | 1].minv); 30 } 31 void PushDown(int rt) { 32 int add = tree[rt].add; 33 if (add) { 34 tree[rt << 1].minv += add; 35 tree[rt << 1].add += add; 36 tree[rt << 1 | 1].minv += add; 37 tree[rt << 1 | 1].add += add; 38 tree[rt].add = 0; 39 } 40 } 41 void Build(int a[], int l, int r, int rt) { 42 tree[rt].add = 0; 43 if (l == r) { 44 tree[rt].minv = a[l]; 45 return ; 46 } 47 define_m; 48 Build(a, lson); 49 Build(a, rson); 50 PushUp(rt); 51 } 52 void Update(int L, int R, int x, int l, int r, int rt) { 53 if (L <= l && r <= R) { 54 tree[rt].minv += x; 55 tree[rt].add += x; 56 return; 57 } 58 define_m; 59 PushDown(rt); 60 if (L <= m) Update(L, R, x, lson); 61 if (R > m) Update(L, R, x, rson); 62 PushUp(rt); 63 } 64 int Query1(int l, int r, int rt) { 65 if (l == r) return tree[rt].minv == 0; 66 define_m; 67 PushDown(rt); 68 if (tree[rt << 1].minv < 0) return Query1(lson); 69 int len = r - l + 1; 70 return len - (len >> 1) + Query1(rson); 71 } 72 int Query2(int l, int r, int rt) { 73 if (l == r) return tree[rt].minv == 0; 74 define_m; 75 PushDown(rt); 76 if (tree[rt << 1 | 1].minv < 2) return Query2(rson); 77 int len = r - l + 1; 78 return (len >> 1) + Query2(lson); 79 } 80 }; 81 int n, q; 82 char s[300010]; 83 int a[300010], b[300010], c[300010]; 84 SegTree G, H; 85 void Init() { 86 for (int i = 0; i < n; i++) { 87 c[i + 1] = c[i]; 88 if (s[i] == '(') c[i + 1]++; 89 else c[i + 1]--; 90 } 91 for (int i = 1; i <= n; i++) { 92 a[i] = c[i] - i; 93 b[i] = c[i]; 94 } 95 } 96 int main() { 97 //freopen("in.txt", "r", stdin); 98 cin >> n >> q; 99 scanf("%s", s); 100 Init(); 101 G.Build(a, 1, n, 1); 102 H.Build(b, 1, n, 1); 103 for (int i = 0; i < q; i++) { 104 int pos, tmp; 105 scanf("%d", &pos); 106 if (s[pos - 1] == '(') { 107 s[pos - 1] = ')'; 108 G.Update(pos, n, -2, 1, n, 1); 109 H.Update(pos, n, -2, 1, n, 1); 110 printf("%d\n", tmp = G.Query1(1, n, 1) + 1); 111 G.Update(tmp, n, 2, 1, n, 1); 112 H.Update(tmp, n, 2, 1, n, 1); 113 s[tmp - 1] = '('; 114 } 115 else { 116 s[pos - 1] = '('; 117 H.Update(pos, n, 2, 1, n, 1); 118 G.Update(pos, n, 2, 1, n, 1); 119 printf("%d\n", tmp = n - H.Query2(1, n, 1) + 1); 120 H.Update(tmp, n, -2, 1, n, 1); 121 G.Update(tmp, n, -2, 1, n, 1); 122 s[tmp - 1] = ')'; 123 } 124 } 125 return 0; 126 }