题目大意:

根据初始给定的合法的小括号排序,每次进行一个操作,将第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 }

 

 posted on 2015-03-24 12:38  Love风吟  阅读(171)  评论(0编辑  收藏  举报