[IOI2018] werewolf 狼人 kruskal重構樹,主席樹
阿新 • • 發佈:2019-02-03
printf 們的 eof html namespace modify 二叉樹 發現 mat
[IOI2018] werewolf 狼人
LG傳送門
kruskal重構樹好題。
日常安利博客文章
這題需要搞兩棵重構樹出來,這兩棵重構樹和我們平時見過的重構樹有點不同(據說叫做點權重構樹?),根據經過我們簡化的建樹方法,這兩棵樹不再是二叉樹,但是仍具有kruskal重構樹的優秀性質,建議結合後面的描述理解。
看這題需要首先我們從\(S\)走到\(T\)轉化為分別從\(S\)和\(T\)出發尋找能共同到達的點,需要快速求出從某個點出發經過點權不大(小)於\(r\)(\(l\))的點,考慮kruskal重構樹。令每條邊的的邊權為所連接兩點的較大(小)值,造兩棵重構樹,這樣就可以像平時一樣直接倍增做了,但是我們發現邊權的信息實際上就是點權的信息,於是我們在建新樹時就不另建新點了,這就是所謂的“點權重構樹”。建出樹處理倍增之後,我們的問題就變成了查詢兩棵樹上兩棵子樹是否有交,用dfs序表達就是一個簡單的二維數點的問題,直接主席樹。
#include <cstdio> #include <cctype> #include <vector> #define R register #define I inline #define B 1000000 using namespace std; const int N = 200003; char buf[B], *p1, *p2; I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1==p2) ? EOF : *p1++; } I int rd() { R int f = 0; R char c = gc(); while (c < 48 || c > 57) c = gc(); while (c > 47 && c < 58) f = f * 10 + (c ^ 48), c = gc(); return f; } int s[N], rt[N], val[N], T; vector <int> g[N]; struct edge { int g, s; }; struct segtree { int p, q, s; }e[N << 5]; struct kruskal { int h[N], f[N], fa[N][20], dfn[N], low[N], E, tim; edge e[N]; I void add(int x, int y) { e[++E] = (edge){y, h[x]}, h[x] = E; } I int find(int x) { R int r = x, y; while (f[r] ^ r) r = f[r]; while (x ^ r) y = f[x], f[x] = r, x = y; return r; } void dfs(int x) { dfn[x] = ++tim; R int i; for (i = 1; i < 20; ++i) fa[x][i] = fa[fa[x][i - 1]][i - 1]; for (i = h[x]; i; i = e[i].s) dfs(e[i].g); low[x] = tim; } }X, Y; int modify(int k, int l, int r, int x) { R int t = ++T; e[t].p = e[k].p, e[t].q = e[k].q, e[t].s = e[k].s + 1; if (l == r) return t; R int m = l + r >> 1; if (x <= m) e[t].p = modify(e[k].p, l, m, x); else e[t].q = modify(e[k].q, m + 1, r, x); return t; } int query(int k, int t, int l, int r, int x, int y) { if (x <= l && r <= y) return e[t].s - e[k].s; R int m = l + r >> 1, o = 0; if (x <= m) o += query(e[k].p, e[t].p, l, m, x, y); if (m < y) o += query(e[k].q, e[t].q, m + 1, r, x, y); return o; } int main() { R int n = rd(), m = rd(), Q = rd(), i, x, y, l, r; for (i = 1; i <= m; ++i) x = rd() + 1, y = rd() + 1, g[x].push_back(y), g[y].push_back(x); for (i = 1; i <= n; ++i) X.f[i] = i, Y.f[i] = i, s[i] = g[i].size(); for (x = n; x; --x) for (i = 0; i < s[x]; ++i) if (g[x][i] > x && (y = X.find(g[x][i])) ^ x) X.add(x, y), X.f[y] = X.fa[y][0] = x; for (x = 1; x <= n; ++x) for (i = 0; i < s[x]; ++i) if (g[x][i] < x && (y = Y.find(g[x][i])) ^ x) Y.add(x, y), Y.f[y] = Y.fa[y][0] = x; X.dfs(1), Y.dfs(n); for (i = 1; i <= n; ++i) val[X.dfn[i]] = Y.dfn[i]; for (i = 1; i <= n; ++i) rt[i] = modify(rt[i - 1], 1, n, val[i]); while (Q--) { x = rd() + 1, y = rd() + 1, l = rd() + 1, r = rd() + 1; for (i = 19; ~i; --i) if (X.fa[x][i] >= l) x = X.fa[x][i]; for (i = 19; ~i; --i) if (Y.fa[y][i] && Y.fa[y][i] <= r) y = Y.fa[y][i]; printf(query(rt[X.dfn[x] - 1], rt[X.low[x]], 1, n, Y.dfn[y], Y.low[y]) ? "1\n" : "0\n"); } return 0; }
[IOI2018] werewolf 狼人 kruskal重構樹,主席樹