[BZOJ2209][[Jsoi2011]括号序列][splay]
题目大意:
给定一个长度为N的括号序列,有三种操作:
询问让 A[x],a[x+1],...,a[y] 这个括号序列合法至少需要修改几个括号。
将 A[x],a[x+1],...,a[y] 翻转
将 A[x],a[x+1],...,a[y] 反转(左右括号互换)
思路:
去除已经匹配的括号后,剩下的括号一定是左边剩下
x
个左括号,右边剩下
删除已经匹配好的就变成:
这时候的答案是:
也就是 (x+1)/2+(y+1)/2 。
对于序列
(l,r)
,
x
是左端点为
序列可以用splay+lazy标志维护。
代码:
#include <bits/stdc++.h>
const int Maxn = 110005;
using namespace std;
namespace IO {
inline char get(void) {
static char buf[1000000], *p1 = buf, *p2 = buf;
if (p1 == p2) {
p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
if (p1 == p2) return EOF;
}
return *p1++;
}
inline void read(int &x) {
x = 0; static char c; bool f = 0;
for (; !(c >= '0' && c <= '9'); c = get()) if (c == '-') f = 1;
for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); if (f) x = -x;
}
inline void read(char &x) {
x = get();
while (x != '(' && x != ')') x = get();
}
inline void write(int x) {
if (!x) return (void)puts("0");
if (x < 0) putchar('-'), x = -x;
static short s[12], t;
while (x) s[++t] = x % 10, x /= 10;
while (t) putchar('0' + s[t--]);
putchar('\n');
}
};
int n, m;
int c[Maxn][2], fa[Maxn], sum[Maxn], sz[Maxn], a[Maxn], rt;
bool rev[Maxn], opp[Maxn];
struct Val {
int l0, l1, r0, r1;
} val[Maxn];
inline int Min(const int &a, const int &b) {
return a < b ? a : b;
}
inline int Max(const int &a, const int &b) {
return a > b ? a : b;
}
inline void pushUp(int x) {
int l = c[x][0], r = c[x][1];
sum[x] = sum[l] + sum[r] + a[x];
sz[x] = sz[l] + sz[r] + 1;
val[x].l0 = Min(val[l].l0, sum[l] + a[x] + val[r].l0);
val[x].l1 = Max(val[l].l1, sum[l] + a[x] + val[r].l1);
val[x].r0 = Min(val[r].r0, sum[r] + a[x] + val[l].r0);
val[x].r1 = Max(val[r].r1, sum[r] + a[x] + val[l].r1);
}
inline void rever(int x) {
rev[x] ^= 1;
swap(val[x].l0, val[x].r0);
swap(val[x].l1, val[x].r1);
}
inline void opposite(int x) {
opp[x] ^= 1; sum[x] = -sum[x]; a[x] = -a[x];
swap(val[x].l0, val[x].l1);
swap(val[x].r0, val[x].r1);
val[x].l0 = -val[x].l0, val[x].l1 = -val[x].l1;
val[x].r0 = -val[x].r0, val[x].r1 = -val[x].r1;
}
inline void pushDown(int x) {
if (rev[x]) {
rever(c[x][0]), rever(c[x][1]);
swap(c[x][0], c[x][1]);
rev[x] = 0;
}
if (opp[x]) {
opposite(c[x][0]), opposite(c[x][1]);
opp[x] = 0;
}
}
inline void rotate(int x, int &k) {
int y = fa[x], z = fa[y], r = (x == c[y][0]);
y == k ? k = x : c[z][!(c[z][0] == y)] = x;
fa[x] = z; fa[y] = x; fa[c[x][r]] = y;
c[y][r ^ 1] = c[x][r]; c[x][r] = y;
pushUp(y), pushUp(x);
}
inline void splay(int x, int &k) {
while (x != k) {
int y = fa[x], z = fa[y];
if (y != k) {
if ((c[y][0] == x) ^ (c[z][0] == y)) rotate(x, k);
else rotate(y, k);
}
rotate(x, k);
}
}
void build(int &k, int l, int r, int last) {
if (l > r) return (void)(k = 0);
k = (l + r) >> 1; fa[k] = last;
if (l == r) {
sum[k] = a[l]; sz[k] = 1;
if (a[l] < 0) val[k].l0 = val[k].r0 = -1;
if (a[l] > 0) val[k].l1 = val[k].r1 = 1;
return;
}
build(c[k][0], l, k - 1, k), build(c[k][1], k + 1, r, k);
pushUp(k);
}
inline int find(int x, int tar) {
pushDown(x); int l = c[x][0], r = c[x][1];
if (tar == sz[l] + 1) return x;
else if (tar <= sz[l]) return find(l, tar);
else return find(r, tar - sz[l] - 1);
}
int main(void) {
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
IO::read(n), IO::read(m);
char op; int t, l, r;
for (int i = 2; i <= n + 1; i++) IO::read(op), a[i] = (op == '(' ? 1 : -1);
build(rt, 1, n + 2, 0);
while (m--) {
IO::read(t), IO::read(l), IO::read(r);
l = find(rt, l); r = find(rt, r + 2);
splay(l, rt); splay(r, c[l][1]);
int k = c[r][0];
if (!t) IO::write((val[k].r1 + 1) / 2 - (val[k].l0 - 1) / 2);
else if (t == 1) opposite(k); else rever(k);
}
return 0;
}
完。
By g1n0st