[BZOJ4573][[Zjoi2016]大森林][LCT建虚点]
题意懒得写了。。。。
思路:
建LCT的时候我们可以引入虚点。对于所有的1操作,新建一个没有权值的虚点,然后对于0操作,可以把新建的节点挂在最后建的虚点上面。由于虚点并不参与权值的计算,所以我们可以把所有操作先离线,然后从左到右把所有树都做一遍,每做到一个操作的时候,把在当前树不存在的虚点(当前树不在某个修改生长节点的操作的影响范围内)都断开,然后连到这个虚点出现之前的虚点上(也就是本该属于这颗树的生长节点)。
然后打个lct就好了。
代码:
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 200010;
inline int Max(const int &a, const int &b) {
return a > b ? a : b;
}
inline int Min(const int &a, const int &b) {
return a < b ? a : b;
}
inline char get(void) {
static char buf[100000], *p1 = buf, *p2 = buf;
if (p1 == p2) {
p2 = (p1 = buf) + fread(buf, 1, 100000, stdin);
if (p1 == p2) return EOF;
}
return *p1++;
}
inline void read(int &x) {
x = 0; static char c;
for (; !(c >= '0' && c <= '9'); c = get());
for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get());
}
inline void write(int x) {
if (!x) return (void) (puts("0"));
static short st[12], top;
while (x) st[++top] = x % 10, x /= 10;
while (top) putchar('0' + st[top--]);
putchar('\n');
}
struct Op {
int pos, op, x, y;
Op(void) {}
Op(const int &pos, const int &op, const int &x, const int &y) : pos(pos), op(op), x(x), y(y) {}
friend bool operator < (const Op &a, const Op &b) {
if (a.pos == b.pos) return a.op < b.op;
else return a.pos < b.pos;
}
} a[Maxn << 2];
int c[Maxn][2], size[Maxn], val[Maxn], fa[Maxn];
inline void pushUp(int x) {
int l = c[x][0], r = c[x][1];
size[x] = size[l] + size[r] + val[x];
}
inline bool Rt(int x) {
return c[fa[x]][0] != x && c[fa[x]][1] != x;
}
inline void rotate(int x) {
int y = fa[x], z = fa[y], l = (c[y][1] == x), r = l ^ 1;
if (!Rt(y)) {
if (c[z][0] == y) c[z][0] = x;
else c[z][1] = x;
}
fa[y] = x; fa[x] = z; fa[c[x][r]] = y;
c[y][l] = c[x][r]; c[x][r] = y;
pushUp(y); pushUp(x);
}
inline void splay(int x) {
while (!Rt(x)) {
int y = fa[x], z = fa[y];
if (!Rt(y)) {
if (c[y][0] == x ^ c[z][0] == y) rotate(x);
else rotate(y);
}
rotate(x);
}
}
inline int access(int x) {
int t;
for (t = 0; x; t = x, x = fa[x])
splay(x), c[x][1] = t, pushUp(x);
return t;
}
inline void cut(int x) {
access(x), splay(x), c[x][0] = fa[c[x][0]] = 0; pushUp(x);
}
inline void link(int x, int y) {
splay(x); fa[x] = y;
}
int p, cnt, m, n, tot, L[Maxn], R[Maxn], id[Maxn], now, ans[Maxn];
inline void add(int o) {
size[n + 1] = val[++n] = o;
}
int main(void) {
//freopen("in.txt", "r", stdin);
read(p), read(m);
add(1); cnt = 1; L[cnt] = id[cnt] = 1; R[cnt] = p;
add(0); now = 2; link(2, 1);
int op, k, x, y;
memset(ans, -1, sizeof ans);
for (int i = 1; i <= m; i++) {
read(op);
if (op == 0) {
read(x), read(y); ++cnt;
L[cnt] = x, R[cnt] = y, add(1), id[cnt] = n;
a[++tot] = Op(1, i - m, n, now);
} else if (op == 1) {
read(x), read(y), read(k);
x = Max(x, L[k]), y = Min(y, R[k]);
if (x <= y) {
add(0);
if (x > 1) link(n, now);
a[++tot] = Op(x, i - m, n, id[k]);
a[++tot] = Op(y + 1, i - m, n, now);
now = n;
}
} else {
read(k), read(x), read(y);
a[++tot] = Op(k, i, id[x], id[y]);
}
}
sort(a + 1, a + tot + 1);
for (int i = 1, k = 1; i <= p; i++)
for (; k <= tot && a[k].pos == i; k++) {
if (a[k].op > 0) {
access(a[k].x), splay(a[k].x), ans[a[k].op] = size[a[k].x];
int t = access(a[k].y); splay(a[k].y), ans[a[k].op] += size[a[k].y];
access(t), splay(t), ans[a[k].op] -= size[t] << 1;
} else {
cut(a[k].x), link(a[k].x, a[k].y);
}
}
for (int i = 1; i <= m; i++)
if (ans[i] != -1) {
write(ans[i]);
}
return 0;
}
完。
By g1n0st