zoukankan      html  css  js  c++  java
  • Flipping Parentheses(CSU1542 线段树)

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1542

    赛后发现这套题是2014东京区域赛的题目,看了排名才发现自己有多low  = =!

    题目大意是这样的,给一个已经匹配了的括号序列,现每次操作就是在位置p将这个位置的括号反转,问要达到将这个序列重新变成匹配序列,最左侧能够操作第几个括号达到目的。

    这里,我的思路是用一个数组a,a[i]表示的是前i个括号,左括号'('与右括号')'的数量之差,题目数据就可以表示为:

    s: (  (  (  )  )  )

    a: 1 2 3 2 1 0

    这样,一个匹配的括号序列对应的数组一定满足两个条件:1、数组没有一个元素为负  2、数组是以0结尾

    现操作时,若是将'(' 转化为')' ,比如将位置4的括号反转,对应数组:

    s: (  (  (  (  )  )

    a: 1 2 3 4 3 2

    可以看做是将数组位置4以后的每个元素都+2(反之,若是')'转化为'(',那么就是那个位置以后每个元素都-2)

    可以看到:

    对应第一种操作,将'(' 转化为')', 要达到匹配序列,只需要将括号序列里的第一个右括号')'翻转即可(因为此时为+2操作,又只可以操作右括号,所以操作第一个必然是最优的)

    对应第二种操作,将')'转化为'(',则是找到从末尾往前找到最早的一个a[p]>=2的位置p,且a[p ~ n] >= 2全部成立,(因为是-2操作,所以必须保证在-2前这个数是>=2的)

    计算时,可以使用线段树(因为有区间操作),节点保存的内容包括左右括号数量之差a,延时标记s,以及f = a[i] - i的值(若a[i] - i < 0,说明在区间[1, i]一定存在一个左括号,供查找第一个左括号时使用),而若要找到从后往前最长连续的a[p ~ n] >= 2的位置p,只需要判断区间的最小值是否>=2,查找方式与上一个类似。

    查询时区间保存的是这个区间的 a 值和 f 值的最小值。区间修改+极值查询。

      1 #include <map>
      2 #include <set>
      3 #include <stack>
      4 #include <queue>
      5 #include <cmath>
      6 #include <ctime>
      7 #include <vector>
      8 #include <cstdio>
      9 #include <cctype>
     10 #include <cstring>
     11 #include <cstdlib>
     12 #include <iostream>
     13 #include <algorithm>
     14 using namespace std;
     15 #define INF 0x3f3f3f3f
     16 #define inf (-((LL)1<<40))
     17 #define lson k<<1, L, mid
     18 #define rson k<<1|1, mid+1, R
     19 #define mem0(a) memset(a,0,sizeof(a))
     20 #define mem1(a) memset(a,-1,sizeof(a))
     21 #define mem(a, b) memset(a, b, sizeof(a))
     22 #define FIN freopen("in.txt", "r", stdin)
     23 #define FOUT freopen("out.txt", "w", stdout)
     24 #define rep(i, a, b) for(int i = a; i <= b; i ++)
     25 
     26 template<class T> T CMP_MIN(T a, T b) { return a < b; }
     27 template<class T> T CMP_MAX(T a, T b) { return a > b; }
     28 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
     29 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
     30 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
     31 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
     32 
     33 //typedef __int64 LL;
     34 typedef long long LL;
     35 const int MAXN = 1010;
     36 const int MAXM = 20010;
     37 const double eps = 1e-4;
     38 
     39 int n, q, p, len;
     40 char s[310000]={"1"};
     41 struct Node {
     42     int f, a, s;
     43 }t[310000<<2];
     44 
     45 char rev(char c) { return (c == '(') ? ')' : '('; }
     46 
     47 void buildTree(int k, int L, int R, int p, int a)
     48 {
     49     t[k].s = 0;
     50     if(L == R) {
     51         t[k].f = a - L; t[k].a = a;
     52         return ;
     53     }
     54     int mid = (L + R) >> 1;
     55     if(p > mid) buildTree(rson, p, a);
     56     else buildTree(lson, p, a);
     57     t[k].f = min(t[k<<1].f, t[k<<1|1].f);
     58     t[k].a = min(t[k<<1].a, t[k<<1|1].a);
     59 }
     60 
     61 void init()
     62 {
     63     mem0(t);
     64     int sum = 0;
     65     len = strlen(s) - 1;
     66     rep (i, 1, len) {
     67         sum += (s[i] == '(') ? 1 : -1;
     68         buildTree(1, 1, len, i, sum);//建树
     69     }
     70 }
     71 
     72 //向下传延时标记
     73 void pushDown(int k)
     74 {
     75     t[k<<1].s += t[k].s; t[k<<1].a += t[k].s; t[k<<1].f += t[k].s;
     76     t[k<<1|1].s += t[k].s; t[k<<1|1].a += t[k].s; t[k<<1|1].f += t[k].s;
     77     t[k].s = 0;
     78 }
     79 
     80 //更新操作,将区间[p, len]的所有值都+val
     81 void update(int k, int L, int R, int p, int val)
     82 {
     83     if(p <= L) {
     84         t[k].s += val;
     85         t[k].a += val;
     86         t[k].f += val;
     87         return ;
     88     }
     89     pushDown(k);
     90     int mid = (L + R) >> 1;
     91     if(p <= mid) update(lson, p, val);//左侧可能需要更新
     92     update(rson, p, val);//右侧是一定要更新的,因为需要更新的区间为[p, len]
     93     t[k].f = min(t[k<<1].f, t[k<<1|1].f);
     94     t[k].a = min(t[k<<1].a, t[k<<1|1].a);
     95 }
     96 
     97 //查询最左侧的右括号
     98 int query1(int k, int L, int R)
     99 {
    100     if(L == R) return L;
    101     int mid = (L + R) >> 1;
    102     pushDown(k);
    103     if(t[k<<1].f < 0) return query1(lson);
    104     return query1(rson);
    105 }
    106 
    107 //查询从len往前连续的最长的满足a>=2的点,也就是最后一个<2的位置+1
    108 int query2(int k, int L, int R)
    109 {
    110     if(L == R) return min(len, L + 1);
    111     int mid = (L + R) >> 1;
    112     pushDown(k);
    113     if(t[k<<1|1].a < 2) return query2(rson);
    114     return query2(lson);
    115 }
    116 
    117 int main()
    118 {
    119     //FIN;
    120     while(~scanf("%d %d%*c %s", &n, &q, s + 1)) {
    121         init();
    122         rep (i, 0, q - 1) {
    123             scanf("%d", &p);
    124             s[p] = rev(s[p]); update(1, 1, len, p, s[p] == ')' ? -2 : 2);
    125             if(s[p] == ')') p = query1(1, 1, len);//find first )
    126             else p = query2(1, 1, len); //find last < 2
    127             s[p] = rev(s[p]); update(1, 1, len, p, s[p] == ')' ? -2 : 2);
    128             printf("%d
    ", p);
    129         }
    130     }
    131     return 0;
    132 }
  • 相关阅读:
    原生态Vim使用快捷键
    Django 搭建博客记(二)
    Django搭建博客记(一)
    草稿
    骨骼动画的实现(OpenGL实现)
    场景内容的再现
    实现Ogre的脚本分离
    Bullet物理引擎在OpenGL中的应用
    linux fork进程请谨慎多个进程/线程共享一个 socket连接,会出现多个进程响应串联的情况。
    多开发机别名跳转脚本片段
  • 原文地址:https://www.cnblogs.com/gj-Acit/p/4361520.html
Copyright © 2011-2022 走看看