[帶有虛點的LCT] BZOJ 4573: 大森林
阿新 • • 發佈:2019-01-25
Solution
要離線來做。
考慮最後一遍是按樹的編號順序一遍掃過。
所以就是要先把兩棵樹之間要改變的資訊都維護出來。
這道題是對生長節點建出一個虛點。
就可以在多棵樹上同時連邊。
#include <bits/stdc++.h>
using namespace std;
const int N = 404040;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
inline void read(int &x) {
static char c; x = 0;
for (c = get(); c < '0' || c > '9'; c = get());
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
struct node *null;
struct node {
node *ch[2];
node *fa;
int size, key, rev;
inline void Reverse(void) {
rev ^= 1; swap(ch[1], ch[0]);
}
inline void PushUp(void) {
size = key + ch[0]->size + ch[1]->size;
}
inline void PushDown(void) {
if (rev) {
ch[0]->Reverse();
ch[1]->Reverse();
rev = 0 ;
}
}
inline void New(int k) {
fa = ch[0] = ch[1] = null;
key = k; rev = 0; PushUp();
}
};
node *p;
node mem[1];
node T[N];
int n, m, opt, x, y, z, c1, cnt, lst, Ocnt;
int L[N], R[N], to[N];
int ans[N];
struct Option {
int pos, id, x, y;
Option(int p = 0, int i = 0, int _x = 0, int _y = 0):pos(p), id(i), x(_x), y(_y) {}
inline friend bool operator <(const Option &a, const Option &b) {
return a.pos == b.pos ? a.id < b.id : a.pos < b.pos;
}
};
Option Q[N];
inline bool IsRoot(node *x) {
return x->fa == null || (x->fa->ch[0] != x && x->fa->ch[1] != x);
}
inline void Rotate(node *x) {
node *y = x->fa, *z = y->fa;
int l = (y->ch[0] != x), r = l ^ 1;
if (!IsRoot(y)) {
if (z->ch[0] == y) z->ch[0] = x;
else z->ch[1] = x;
}
x->fa = z; y->fa = x; x->ch[r]->fa = y;
y->ch[l] = x->ch[r]; x->ch[r] = y;
y->PushUp(); x->PushUp();
}
inline void Down(node *x) {
if (!IsRoot(x)) Down(x->fa);
x->PushDown();
}
inline void Splay(node *x) {
Down(x);
while (!IsRoot(x)) {
node *y = x->fa, *z= y->fa;
if (!IsRoot(y)) {
if (z->ch[0] == y ^ y->ch[0] == x) Rotate(x);
else Rotate(y);
}
Rotate(x);
}
}
inline node *Access(node *x) {
node *y;
for (y = null; x != null; x = x->fa) {
Splay(x); x->ch[1] = y;
x->PushUp(); y = x;
}
return y;
}
inline void MakeRoot(node *x) {
Access(x); Splay(x); x->Reverse();
}
inline void Link(node *x, node *y) {
MakeRoot(x); x->fa = y;
}
inline void Cut(node *x, node *y) {
MakeRoot(x); Access(y); Splay(y);
x->fa = y->ch[0] = null; y->PushUp();
}
inline void Cut(node *x) {
Access(x); Splay(x);
x->ch[0] = x->ch[0]->fa = null;
x->PushUp();
}
void Init(void) {
null = mem;
null->fa = null->ch[0] = null->ch[1] = null;
null->size = null->key = 0;
}
int main(void) {
read(n); read(m); c1 = 1; Init();
to[c1] = L[c1] = 1; R[c1] = n;
T[++cnt].New(1);
T[lst = ++cnt].New(0);
Link(T + 2, T + 1);
for (int i = 1; i <= m; i++) {
read(opt);
if (opt == 0) {
read(L[++c1]); read(R[c1]);
T[++cnt].New(1); to[c1] = cnt;
Q[++Ocnt] = Option(1, i - m, cnt, lst);
} else if (opt == 1) {
read(x); read(y); read(z);
x = max(x, L[z]); y = min(y, R[z]);
if (x <= y) {
T[++cnt].New(0);
if (x > 1) Link(T + cnt, T + lst);
Q[++Ocnt] = Option(x, i - m, cnt, to[z]);
Q[++Ocnt] = Option(y + 1, i - m, cnt, lst);
lst = cnt;
}
} else {
read(x); read(y); read(z);
Q[++Ocnt] = Option(x, i, to[y], to[z]);
}
}
for (int i = 1; i <= m; i++) ans[i] = -1;
sort(Q + 1, Q + Ocnt + 1);
for (int i = 1, p1 = 1; i <= m; i++)
for (; p1 <= Ocnt && Q[p1].pos == i; p1++) {
if (Q[p1].id > 0) {
Access(T + Q[p1].x); Splay(T + Q[p1].x); ans[Q[p1].id] = T[Q[p1].x].size;
p = Access(T + Q[p1].y); Splay(T + Q[p1].y); ans[Q[p1].id] += T[Q[p1].y].size;
Access(p); Splay(p); ans[Q[p1].id] -= 2 * p->size;
} else {
Cut(T + Q[p1].x); Link(T + Q[p1].x, T + Q[p1].y);
}
}
for (int i = 1; i <= m; i++)
if (~ans[i]) printf("%d\n", ans[i]);
return 0;
}