您的位置:首页 > Web前端 > JavaScript

[BZOJ2209][[Jsoi2011]括号序列][splay]

2017-03-11 15:53 417 查看

[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个左括号,右边剩下y个右括号且x,y奇偶性相同。比如下面这个括号序列。

))()()())()(

删除已经匹配好的就变成:

)))(,x=3,y=1

这时候的答案是:

{x/2+y/2x/2+1+y/2+1x,y%2=0x,y%2=1

也就是(x+1)/2+(y+1)/2。

对于序列(l,r),x是左端点为l,右端点<=r时,序列中右括号比左括号多的个数的最大值(>=0)。当将”(=1”,”)=−1”时,实际上求的就是最小左字段和,而y求的则是最大右字段和。注意到题目中有反转的操作,因此最大左字段和和最小右字段和也应当保存下来。

序列可以用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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  oi bzoj splay 维护序列