BZOJ2329 [HNOI2011]括号修复

把左括号看做$1$,右括号看做$-1$,于是查询操作等于查询一个区间左边右边最大(最小)子段和

支持区间翻转,反转,覆盖操作。。。注意如果有覆盖操作,之前的操作全部作废了。。。于是在下传标记的时候要最后做。。。

  1 /**************************************************************
  2     Problem: 2329
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:4252 ms
  7     Memory:7352 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <algorithm>
 12
 13 #define _max(x, y) (x > y ? x : y)
 14 #define _min(x, y) (x < y ? x : y)
 15 using namespace std;
 16 const int N = 1e5 + 5;
 17
 18 int read();
 19 int get_c();
 20 int get_op();
 21
 22 namespace treap {
 23     struct node;
 24     node *root, *null;
 25
 26     struct node {
 27         node *ls, *rs;
 28         int val, rev, inv, fill, maxl, maxr, minl, minr, sum, sz;
 29
 30         #define Len (1 << 16)
 31         inline void* operator new(size_t, int _v = 0) {
 32             static node *mempool, *c;
 33             if (mempool == c)
 34                 mempool = (c = new node[Len]) + Len;
 35             c -> ls = c -> rs = null;
 36             c -> val = c -> sum = _v, c -> rev = c -> inv = c -> fill = 0;
 37             c -> maxl = c -> maxr =  c -> minl = c -> minr = 0;
 38             c -> sz = 1;
 39             return c++;
 40         }
 41         #undef Len
 42
 43         inline void reverse() {
 44             rev ^= 1;
 45             swap(ls, rs);
 46             swap(minl, minr), swap(maxl, maxr);
 47         }
 48         inline void inverse() {
 49             inv ^= 1;
 50             fill = -fill, val = -val, sum = -sum;
 51             swap(maxl, minl), maxl = -maxl, minl = -minl;
 52             swap(maxr, minr), maxr = -maxr, minr = -minr;
 53         }
 54         inline void replace(int t) {
 55             fill = val = t, sum = sz * t;
 56             maxl = maxr = sz * (t == 1);
 57             minl = minr = -sz * (t == -1);
 58         }
 59
 60         inline node* update() {
 61             sz = ls -> sz + rs -> sz + 1;
 62             sum = ls -> sum + rs -> sum + val;
 63             maxl = _max(ls -> maxl, ls -> sum + val + _max(0, rs -> maxl));
 64             minl = _min(ls -> minl, ls -> sum + val + _min(0, rs -> minl));
 65             maxr = _max(rs -> maxr, rs -> sum + val + _max(0, ls -> maxr));
 66             minr = _min(rs -> minr, rs -> sum + val + _min(0, ls -> minr));
 67             return this;
 68         }
 69         inline node* push() {
 70             if (rev) {
 71                 ls -> reverse(), rs -> reverse();
 72                 rev = 0;
 73             }
 74             if (inv) {
 75                 ls -> inverse(), rs -> inverse();
 76                 inv = 0;
 77             }
 78             if (fill) {
 79                 ls -> replace(fill), rs -> replace(fill);
 80                 fill = 0;
 81             }
 82             return this;
 83         }
 84     };
 85
 86     inline void init() {
 87         null = new()node;
 88         null -> ls = null -> rs = null;
 89         null -> sz = null -> val = 0;
 90     }
 91
 92     inline unsigned int Rand() {
 93         static unsigned int res = 2333;
 94         return res += res << 2 | 1;
 95     }
 96     inline int random(int x, int y) {
 97         return Rand() % (x + y) < x;
 98     }
 99
100     void build(node *&p, int l, int r, int *a) {
101         if (l > r) {
102             p = null;
103             return;
104         }
105         p = new(a[l + r >> 1])node;
106         if (l == r) {
107             p -> update();
108             return;
109         }
110         build(p -> ls, l, (l + r >> 1) - 1, a);
111         build(p -> rs, (l + r >> 1) + 1, r, a);
112         p -> update();
113     }
114
115     void merge(node *&p, node *x, node *y) {
116         if (x == null || y == null)
117             p = x == null ? y -> push() : x -> push();
118         else if (random(x -> sz, y -> sz)) {
119             p = x -> push();
120             merge(p -> rs, x -> rs, y);
121         } else {
122             p = y -> push();
123             merge(p -> ls, x, y -> ls);
124         }
125         p -> update();
126     }
127
128     void split(node *p, node *&x, node *&y, int k) {
129         if (!k) {
130             x = null, y = p -> push();
131             return;
132         }
133         if (k == p -> sz) {
134             x = p -> push(), y = null;
135             return;
136         }
137         if (p -> ls -> sz >= k) {
138             y = p -> push();
139             split(p -> ls, x, y -> ls, k);
140             y -> update();
141         } else {
142             x = p -> push();
143             split(p -> rs, x -> rs, y, k - p -> ls -> sz - 1);
144             x -> update();
145         }
146     }
147 }
148 using namespace treap;
149
150 int n;
151 int a[N];
152
153 int main() {
154     int Q, i, oper, l, r;
155     node *x, *y, *z;
156     init();
157     n = read(), Q = read();
158     for (i = 1; i <= n; ++i) a[i] = get_c();
159     build(root, 1, n, a);
160     while (Q--) {
161         oper = get_op(), l = read(), r = read();
162         split(root, x, y, l - 1), split(y, y, z, r - l + 1);
163         if (oper == 0) y -> replace(get_c());
164         else if (oper == 1) printf("%d\n", (y -> maxr + 1) / 2 - (y -> minl - 1) / 2);
165         else if (oper == 2) y -> reverse();
166         else if (oper == 3) y -> inverse();
167         merge(root, x, y -> push()), merge(root, root, z);
168     }
169     return 0;
170 }
171
172 inline int read() {
173     register int x = 0;
174     register char ch = getchar();
175     while (ch < ‘0‘ || ‘9‘ < ch) ch = getchar();
176     while (‘0‘ <= ch && ch <= ‘9‘)
177         x = x * 10 + ch - ‘0‘, ch = getchar();
178     return x;
179 }
180
181 inline int get_c() {
182     register char ch = getchar();
183     while (ch != ‘(‘ && ch != ‘)‘) ch = getchar();
184     return ch == ‘(‘ ? 1 : -1;
185 }
186
187 inline int get_op() {
188     register char ch = getchar();
189     while (ch != ‘R‘ && ch != ‘Q‘ && ch != ‘S‘ && ch != ‘I‘) ch = getchar();
190     if (ch == ‘R‘) return 0;
191     if (ch == ‘Q‘) return 1;
192     if (ch == ‘S‘) return 2;
193     if (ch == ‘I‘) return 3;
194 }

时间: 2024-12-13 20:08:31

BZOJ2329 [HNOI2011]括号修复的相关文章

bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)

http://www.lydsy.com/JudgeOnline/problem.php?id=2329 需要改变的括号序列一定长这样 :)))((( 最少改变次数= 多余的‘)’/2 [上取整] + 多余的‘(’ /2 [上取整] 把 ‘)’ 看做1,‘(’ 看做-1 那么最少改变次数=最大前缀和/2 [上取整]+ 最小后缀和/2 [上取整] 覆盖标记的优先级高于翻转标记和取反标记 即下放覆盖标记时,同时清空翻转标记和取反标记 且先下放覆盖标记 翻转: 最大前缀和 和 最大后缀和 交换 最小前

bzoj2329: [HNOI2011]括号修复 Splay

神题. 用-1表示左括号,1表示右括号,lmax表示从左开始的最大连续和,rmin表示从右开始的最小连续和,答案为(lmax+1)/2+(-rmin+1)/2. Splay维护即可. #include<bits/stdc++.h> #define L(t) (t)->c[0] #define R(t) (t)->c[1] #define Z(t) (L(t)->s+1) #define M (l+r>>1) using namespace std; struct

BZOJ2329 HNOI2011 括号修复 平衡树

题意:给定一个由(,)组成的括号序列,维护:1.将[a,b]修改为同一种半括号  2.将[a,b]翻转  3.将[a,b]的(变为),)变为(  4.求[a,b]最少要添加多少个括号才能合法 题解: 不算太裸的平衡树……论标记的正确打法. 对于一个括号序列,我们总能简化成一个左边全是右括号,右边全是左括号的序列,像酱紫:)))))(((((.当然有可能是没有左括号或者右括号的 我们定义)==-1,(==1.然后我们用打标记的方法来维护从左起的最小序列和lmin和从右起的最大序列和rmax,显然这

BZOJ 2329: [HNOI2011]括号修复( splay )

把括号序列后一定是))))((((这种形式的..所以维护一个最大前缀和l, 最大后缀和r就可以了..答案就是(l+1)/2+(r+1)/2...用splay维护,O(NlogN). 其实还是挺好写的, 只是我傻X -------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstrin

●BZOJ 2329 [HNOI2011]括号修复.cpp

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 题解: Splay 类似 BZOJ 2329 [HNOI2011]括号修复 只是多了一个Replace(替换)操作, 然后就要主要lazy标记之间的影响了. 1).Replace可以直接覆盖另外两个标记, 2).当已经有Replace标记,再覆盖Invert标记时,直接把Replace标记取反即可;在覆盖Swap标记时,Replace标记不变. 代码: #include<cstdio

BZOJ 2329: [HNOI2011]括号修复 [splay 括号]

题目描述 一个合法的括号序列是这样定义的: 空串是合法的. 如果字符串 S 是合法的,则(S)也是合法的. 如果字符串 A 和 B 是合法的,则 AB 也是合法的. 现在给你一个长度为 N 的由‘('和‘)'组成的字符串,位置标号从 1 到 N.对这个字符串有下列四种操作: Replace a b c:将[a,b]之间的所有括号改成 c.例如:假设原来的字符串为:))())())(,那么执行操作 Replace 2 7 ( 后原来的字符串变为:)(((((()(. Swap a b:将[a,b]

【BZOJ】2329: [HNOI2011]括号修复(splay+特殊的技巧)

http://www.lydsy.com/JudgeOnline/problem.php?id=2329 和前一题一样,不就多了个replace操作吗.好,就打一下. 然后交上去wa了.................... 看了题解,好神奇! 记住:以后pushdown的tag要考虑先后顺序! 因为invert和swap操作谁先谁后没有关系,那么考虑invert和replace这两个有冲突的关系 为什么有冲突呢?因为假如你replace的标记在先,invert标记在后,但是invert在pus

2329: [HNOI2011]括号修复

传送魔法 一开始以为可以直接线段树的,好像还是不行--还是得用Spaly,然后就没啥了. #include<cstdio> #include<algorithm> #define MN 210000 using namespace std; inline int read(){ int ca=getchar(),p=0; while (ca<'0'||ca>'9') ca=getchar(); while (ca>='0'&&ca<='9')

[HNOI2011][bzoj 2329] 括号修复 [splay+前缀和]

题面: http://www.lydsy.com/JudgeOnline/problem.php?id=2329 思路: 显然,操作4中输出补全的最小费用是关键 这决定了我们不可能在splay上只维护1-2个值. 考虑一段括号序列,将其中所有合法序列删去以后,留下的一定是形如 ))))))((( 的序列 因此首先考虑将每段区间左侧不匹配的括号数和右侧不匹配的括号数记录下来,分别为 left[l,r] 和 right[l,r] 此时除了Invert操作以外已经可以满足 但是对于Invert操作,对