Flipping Parentheses (線段樹 單點更新 區間查詢)
阿新 • • 發佈:2019-01-22
題目大意 : 給一個括號已經匹配好的序列,每次反轉一個括號, 然後讓你再次反轉一個括號再次使得括號匹配,並且你反轉的位置儘可能的靠近左端。
可以對於每個位置,記錄它之前的左括號的數量減去右括號的數量,這個序列合法的條件就是每個位置不會出現值小於0的情況。最後一位一定是0.
如果他反轉的是右括號,這個位置變成左括號之後 你需要找到一個左括號把它反成右括號。而你需要找的位置就是從最後一個往前最後一個為大於等於2的位置。
如果他反轉的是左括號,那就找到最左邊的右括號。
兩種情況分別都可以用線段樹維護
#include <algorithm> #include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #define MAX 0x3f3f3f3f #define N 300005 #define mod 1000000007 #define lson o<<1, l, m #define rson o<<1|1, m + 1, r typedef long long LL; const double pi = acos(-1.0); using namespace std; int n, q, X, A, B, mi[N<<2], add[N<<2]; bool E, v[N<<2]; char s[N]; void down(int o) { if(add[o]) { add[o<<1] += add[o]; add[o<<1|1] += add[o]; mi[o<<1] += add[o]; mi[o<<1|1] += add[o]; add[o] = 0; } } void modify(int o, int l, int r) { if(l == r) v[o] = E; else { int m = (l+r) >> 1; if(X <= m) modify(lson); else modify(rson); v[o] = v[o<<1] | v[o<<1|1]; } } void build(int o, int l, int r) { if(l == r) mi[o] = A; else { int m = (l+r) >> 1; if(X <= m) build(lson); else build(rson); mi[o] = min(mi[o<<1], mi[o<<1|1]); } } void update(int o, int l, int r) { if(X <= l && r <= n) { add[o] += B; mi[o] += B; } else { down(o); int m = (l+r) >> 1; if(X <= m) update(lson); if(m < n ) update(rson); mi[o] = min(mi[o<<1], mi[o<<1|1]); } } int Find(int o, int l, int r) { if(l == r) return l; else { int m = (l+r) >> 1; if(v[o<<1]) return Find(lson); else return Find(rson); } } int query(int o, int l, int r) { if(l == r) return mi[o] >= 2; else { down(o); int m = (l+r) >> 1, res = 0; if(mi[o<<1|1] >= 2) { res += r-m; res += query(lson); } else res += query(rson); return res; } } int main() { //freopen("in.txt", "r", stdin); //read(n), read(q); scanf("%d%d", &n, &q); scanf("%s", s+1); int zuo = 0, you = 0; for(X = 1; X <= n; X++) { if(s[X] == '(') zuo++; else { you++; E = 1, modify(1, 1, n); } A = zuo - you; build(1, 1, n); } while(q--) { scanf("%d", &X); if(s[X] == '(') { s[X] = ')'; // 修改成右括號 B = -2, update(1, 1, n); E = 1, modify(1, 1, n); X = Find(1, 1, n); // 找到第一個右括號的位置 printf("%d\n", X); s[X] = '('; // 將它改為左括號 B = 2, update(1, 1, n); E = 0, modify(1, 1, n); } else { s[X] = '('; //修改成左括號 B = 2, update(1, 1, n); E = 0, modify(1, 1, n); X = n - query(1, 1, n) + 1; // 找到滿足條件的最左邊的左括號 printf("%d\n", X); s[X] = ')'; //將它修改成右括號 B = -2, update(1, 1, n); E = 1, modify(1, 1, n); } } return 0; }