牛客练习赛70 D 数树
数树
https://ac.nowcoder.com/acm/contest/7509/D
没看到题目中条件保证是一颗森林,自行加强题目。
这里采用时间线段树+回退并查集来解决。
并查集可以O(1)的插入,很难O(1)的支持删除操作,但是可以回退。
我们使用时间线段树,将所有操作锁定为插入操作,使用回退并查集维护即可。
复杂度O(nlogn)。
#include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt * 2 #define rson rt * 2 + 1 #define MP make_pair const int N = 2e5 + 100; int n, tp, tt; int op[N], uu[N], vv[N], id[N], has[N], ans[N]; pair<int, int> mp[N]; int tim[N]; struct node { int op, u, v; node() {} node(int op, int u, int v) :op(op), u(u), v(v) {} }; vector<node> V[N * 4], G[N * 4]; void insert(int rl, int rr, node x, int l, int r, int rt) { if (rl == l && rr == r) { V[rt].push_back(x); return; } int m = (l + r) / 2; if (rr <= m) insert(rl, rr, x, l, m, lson); else if (m < rl) insert(rl, rr, x, m + 1, r, rson); else { insert(rl, m, x, l, m, lson); insert(m + 1, rr, x, m + 1, r, rson); } } int fa[N], sz[N], sum; void change(int op, int id, int x, vector<node> &V) { if (op == 1) { V.push_back(node(op, id, fa[id])); fa[id] = x; } if (op == 2) { V.push_back(node(op, id, sz[id])); sz[id] = x; } if (op == 3) { V.push_back(node(op, 0, sum)); sum = x; } } void recover(node x) { if (x.op == 1) { fa[x.u] = x.v; } if (x.op == 2) { sz[x.u] = x.v; } if (x.op == 3) { sum = x.v; } } int find(int x, vector<node> &V) { if (x == fa[x]) return x; int f = find(fa[x], V); change(1, x, f, V); return f; } void join(int u, int v, vector<node> &V) { u = find(u, V); v = find(v, V); if (u == v) return; if (sz[u] == 1 && sz[v] == 1) change(3, 0, sum + 1, V); if (sz[u] > 1 && sz[v] > 1) change(3, 0, sum - 1, V); change(1, u, v, V); change(2, v, sz[u] + sz[v], V); } void query(int l, int r, int rt) { for (node x : V[rt]) { if (x.op == 1) { join(x.u, x.v, G[rt]); } } if (l == r) { for (node x : V[rt]) { if (x.op == 3) { ans[l] = sum; } } } else { int m = (l + r) / 2; query(l, m, lson); query(m + 1, r, rson); } for (int i = G[rt].size() - 1; i >= 0; i--) { recover(G[rt][i]); } G[rt].clear(); V[rt].clear(); vector<node> v, g; swap(G[rt], g); swap(V[rt], v); } int main() { //freopen("0.txt", "r", stdin); scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", op + i); if (op[i] != 3) { scanf("%d%d", uu + i, vv + i); has[++tp] = uu[i]; has[++tp] = vv[i]; } } sort(has + 1, has + tp + 1); tp = unique(has + 1, has + tp + 1) - has; for (int i = 1; i <= n; i++) { if (op[i] != 3) { uu[i] = lower_bound(has + 1, has + tp, uu[i]) - has; vv[i] = lower_bound(has + 1, has + tp, vv[i]) - has; if (uu[i] > vv[i]) swap(uu[i], vv[i]); mp[++tt] = MP(uu[i], vv[i]); } } sort(mp + 1, mp + tt + 1); tt = unique(mp + 1, mp + tt + 1) - mp; for (int i = 1; i <= n; i++) { if (op[i] == 3) continue; int id = lower_bound(mp + 1, mp + tt, MP(uu[i], vv[i])) - mp; if (op[i] == 1) { if (tim[id] == 0) { tim[id] = i; } } else { if (tim[id] != 0) { insert(tim[id], i, node(1, uu[i], vv[i]), 1, n, 1); } tim[id] = 0; } } for (int i = 1; i <= n; i++) { if (op[i] == 3) { insert(i, i, node(3, 0, 0), 1, n, 1); } else if (op[i] == 1) { int id = lower_bound(mp + 1, mp + tt, MP(uu[i], vv[i])) - mp; if (tim[id] == i) { insert(i, n, node(1, uu[i], vv[i]), 1, n, 1); } } } for (int i = 1; i <= tp; i++) fa[i] = i, sz[i] = 1; query(1, n, 1); for (int i = 1; i <= n; i++) if (op[i] == 3) printf("%d\n", ans[i]); return 0; }