1. 程式人生 > >[帶有虛點的LCT] BZOJ 4573: 大森林

[帶有虛點的LCT] BZOJ 4573: 大森林

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; }