题目大意:
根据初始给定的合法的小括号排序,每次进行一个操作,将第a位的括号反向,找到一个尽可能靠前的括号反向后是整个括号排列合法
数据量十分大,不断进行查询,要用线段树进行logn的复杂度的查询
首先最简单的考虑 '('->')' , 稍微想一下可以知道因为要尽可能靠前,所以其实把最前面的那个 )改成 ( 即可,这里我就用 minn[] 数组记录区间内最早出现的 ) 的下标
然后是考虑 ')'->'(' , 我们可以倒着字符串来看,从后往前每次出现一个 ) 都记录加1 , 那么每次遇到一个 ( 就抵消1 , 那么当遇到 (没东西抵消时,说明这个是离尾部最远的不合法的符号,离尾部最远,那么就可以理解为离起点最近
具体怎么写的话就是可以将 '(' 看作 1 , ')' 看作-1 , 利用一个数组 minsum[] 记录区间内前缀和的最小值
对于一个线段树来说如果那个符号的位置出现在左子树的区间上,那么右子树中的所有前缀和都必然 >=2
所以查询就很容易得到 if(sum[rs] < 2) ans = 右子树的查询,else ans = 左子树的查询
但再想想的话,返回的值不能是当前下标 , 而是下标+1;
因为根据前面所讲,你所需要修改的位置 i 是 i 后面的数相加和正好为0的
也就是说到达i的前缀之和正好是2
而 第 i-1 位的前缀和正好为1,每次不断判断找 < 2的点,那么最后查询到的是i-1
也就是必须要加个1才能到达我需要改的位置
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 6 #define ls o<<1 7 #define rs o<<1|1 8 #define define_m int m=(l+r)>>1 9 const int N = 300010; 10 const int INF = 0x3f3f3f3f; 11 int minn[N<<2] , minsum[N<<2] , a[N] , add[N<<2]; 12 char str[N]; 13 14 void push_up(int o) 15 { 16 minsum[o]=min(minsum[ls] , minsum[rs]); 17 minn[o]=min(minn[ls] , minn[rs]); 18 } 19 20 void push_down(int o) 21 { 22 if(add[o]){ 23 add[ls]+=add[o]; 24 add[rs]+=add[o]; 25 minsum[ls]+=add[o]; 26 minsum[rs]+=add[o]; 27 add[o]=0; 28 } 29 } 30 31 void build(int o , int l , int r) 32 { 33 add[o]=0; 34 if(l == r) { 35 minn[o] = str[l]==')'?l:INF; 36 minsum[o]=a[l]; 37 return; 38 } 39 define_m; 40 build(ls , l , m); 41 build(rs , m+1 , r); 42 push_up(o); 43 } 44 45 void update(int o , int l , int r , int s , int t , int v) 46 { 47 if(l>=s && r<=t){ 48 minsum[o]+=v; 49 add[o]+=v; 50 return; 51 } 52 push_down(o); 53 define_m; 54 if(m>=s) update(ls , l , m , s , t , v); 55 if(m<t) update(rs , m+1 , r ,s , t , v); 56 minsum[o]=min(minsum[ls] , minsum[rs]); 57 } 58 59 void update1(int o , int l , int r , int pos) 60 { 61 if(l == r && l == pos){ 62 minn[o] = (str[l]==')'?l:INF); 63 return; 64 } 65 push_down(o); 66 define_m; 67 if(m >= pos) update1(ls , l , m ,pos); 68 else update1(rs , m+1 , r , pos); 69 minn[o] = min(minn[ls] , minn[rs]); 70 } 71 72 int query(int o , int l , int r , int n) 73 { 74 // cout<<"o: "<<o<<" l: "<<l<< " r: "<<r<<" left: "<<minsum[ls]<<" right: "<<minsum[rs]<<endl; 75 if(l==r) return l+1; 76 push_down(o); 77 define_m; 78 if(minsum[rs]<2) return query(rs , m+1 , r , n); 79 else return query(ls , l , m , n); 80 } 81 82 int main() 83 { 84 // freopen("a.in" , "r" , stdin); 85 int n , m , pos; 86 while(scanf("%d%d" , &n , &m) != EOF) 87 { 88 scanf("%s" , str+1); 89 for(int i=1 ; i<=n ; i++){ 90 a[i]=a[i-1]+(str[i]=='('?1:-1); 91 } 92 build(1 , 1 , n); 93 int res; 94 for(int i=0 ; i<m ; i++){ 95 scanf("%d" , &pos); 96 if(str[pos] == '('){ 97 str[pos] = ')'; 98 update1(1 , 1 , n , pos); 99 update(1 , 1 , n , pos , n , -2); 100 res = minn[1]; 101 str[res] = '('; 102 update1(1 , 1 , n , res); 103 } 104 else{ 105 str[pos] = '('; 106 update1(1 , 1 , n , pos); 107 update(1 , 1 , n , pos , n , 2); 108 res = query(1 , 1 , n , n); 109 str[res] = ')'; 110 update1(1 , 1 , n , res); 111 } 112 update(1 , 1 , n , res , n , str[res] == '('?2:-2); 113 printf("%d\n" , res); 114 } 115 } 116 return 0; 117 }