题目大意:

根据初始给定的合法的小括号排序,每次进行一个操作,将第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 = ;
  10. const int INF = 0x3f3f3f3f;
  11. int minn[N<<] , minsum[N<<] , a[N] , add[N<<];
  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]=;
  28. }
  29. }
  30.  
  31. void build(int o , int l , int r)
  32. {
  33. add[o]=;
  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+ , 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+ , 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+ , 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+;
  76. push_down(o);
  77. define_m;
  78. if(minsum[rs]<) return query(rs , m+ , 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+);
  89. for(int i= ; i<=n ; i++){
  90. a[i]=a[i-]+(str[i]=='('?:-);
  91. }
  92. build( , , n);
  93. int res;
  94. for(int i= ; i<m ; i++){
  95. scanf("%d" , &pos);
  96. if(str[pos] == '('){
  97. str[pos] = ')';
  98. update1( , , n , pos);
  99. update( , , n , pos , n , -);
  100. res = minn[];
  101. str[res] = '(';
  102. update1( , , n , res);
  103. }
  104. else{
  105. str[pos] = '(';
  106. update1( , , n , pos);
  107. update( , , n , pos , n , );
  108. res = query( , , n , n);
  109. str[res] = ')';
  110. update1( , , n , res);
  111. }
  112. update( , , n , res , n , str[res] == '('?:-);
  113. printf("%d\n" , res);
  114. }
  115. }
  116. return ;
  117. }

CSUOJ 1542 线段树解决括号反向问题的更多相关文章

  1. hdu 1542 线段树扫描(面积)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  2. bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治

    这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...

  3. BZOJ 1095 捉迷藏(线段树维护括号序列)

    对于树的一个括号序列,树上两点的距离就是在括号序列中两点之间的括号匹配完之后的括号数... 由此可以得出线段树的做法.. #include<cstdio> #include<iost ...

  4. [板子]用线段树解决ST表问题

    ST表可以参考:http://blog.csdn.net/whistlena/article/details/52191463 简单说就是区间RMQ最值问题. 对解决这种问题,线段树不用用啥啊. 扔一 ...

  5. hdu 1542 线段树+扫描线 学习

    学习扫描线ing... 玄学的东西... 扫描线其实就是用一条假想的线去扫描一堆矩形,借以求出他们的面积或周长(这一篇是面积,下一篇是周长) 扫描线求面积的主要思想就是对一个二维的矩形的某一维上建立一 ...

  6. hdu 1542 线段树之扫描线之面积并

    点击打开链接 题意:给你n个矩形,求它们的面积,反复的不反复计算 思路:用线段树的扫描线完毕.将X坐标离散化后,从下到上扫描矩形,进行各种处理,看代码凝视把 #include <stdio.h& ...

  7. BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)

    这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...

  8. BZOJ1095: [ZJOI2007]Hide 捉迷藏【线段树维护括号序列】【思维好题】

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  9. CodeForces-380C:Sereja and Brackets(线段树与括号序列)

    Sereja has a bracket sequence s1, s2, ..., sn, or, in other words, a string s of length n, consistin ...

随机推荐

  1. Windows7运行无法记录历史命令问题解决

    Windows7运行无法记录历史命令,每次都需要手动敲命令,解决方法如下: 1.任务栏中右键,选择"属性"菜单: 2.在弹出框中的"[开始]菜单"选项卡的隐私区 ...

  2. eclipse控制台不显示输出的解决办法

    1.进windows菜单 -> show view -> console2.还是windows菜单里面 -> preferences -> 打开左边的run/debug -&g ...

  3. iOS开发之邮件发送代码

    邮件发送功能是由MessageUI Framework提供的,这个框架是iPhone sdk中最简单的框.由一个类.一个视图控制器,一个protocol组成. 一.创建视图控制器: MFMailCom ...

  4. vue组件、数据解析的实现思想猜想与实践

    Vue的全局组件,在注册后,可在全局范围内无限次使用,猜想是利用了闭包"可以保持形参"的特性,使初始化时的作用域得意保存,下面用原生js和部分jquery代码模拟了数据解析和组件渲 ...

  5. js实现表单checkbox的单选,全选

    全选&单选 //<input type="checkbox" name="" class="quan" value=" ...

  6. orcale 数据库的一些知识

    最近学了一些Oracle数据库的知识,我想自己整理一下,以后也方便自己查阅的. orcale 数据库登录(tiger) 1. sql plus 登录 用户名: sys 口令: 主机字符串:orcl a ...

  7. 面试题6:输入一个链表,按链表值从尾到头的顺序返回一个ArrayList

    题目 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList. 思路 使用栈依次存放输入的链表顺序的值,然后依次出栈便是链表的逆序. 代码 import java.util.ArrayList ...

  8. iOS---开发实用传感器

    传感器 1.什么是传感器 传感器是一种感应\检测装置, 目前已经广泛应用于智能手机上 2.传感器的作用 用于感应\检测设备周边的信息 不同类型的传感器, 检测的信息也不一样 iPhone中的下面现象都 ...

  9. thinkphp5 404 file_put_contents 无法打开流:权限被拒绝

    如果你用TP的时间比较长,或者说你比较了解TP的人都会知道,TP的runtime它需要的权限是很大的,如果你只给一般权限肯定是不行的,通常都是给runtime权限:777: linux命令如下: cd ...

  10. Bash Template

    #/bin/bash #set -x set -e usage() { cat <<EOF Usage: `basename $` [OPTIONS] <non-option arg ...