Codeforces Gym 101194G Pandaria (2016 ACM-ICPC EC-Final G題, 並查集 + 線段樹合並)
阿新 • • 發佈:2018-03-04
body end highlight 題目 efi 預處理 ++i sin const
題目鏈接 2016 ACM-ICPC EC-Final Problem G
題意 給定一個無向圖。每個點有一種顏色。
現在給定$q$個詢問,每次詢問$x$和$w$,求所有能通過邊權值不超過w的邊走到$x$的點的集合中,哪一種顏色的點出現的次數最多。
次數相同時輸出編號最小的那個顏色。強制在線。
求哪種顏色可以用線段樹合並搞定。
關鍵是這個強制在線。
當每次詢問的時候,我們先要求出最小生成樹在哪個時刻恰好把邊權值不超過$w$的邊都用並查集合並了。
在做最小生成樹的時候每合並兩個節點,另外開一個新的結點,原來兩個點的父親都指向這個新的結點。
然後倍增預處理,用類似求$LCA$的方法來得到詢問的那個時刻。
時間復雜度$O(nlogn)$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 2e5 + 10; const int M = N * 20; struct node{ int x, y, z; void scan(){ scanf("%d%d%d", &x, &y, &z); } friend bool operator < (const node &a, const node &b){ return a.z < b.z; } } e[N]; int T, ca = 0; int tot; int n, m, q, ans; int c[N], root[N], v[N], father[N]; int ls[M], rs[M], mx[M], ret[M]; int id, res[N]; int f[N][19]; int getfather(int x){ return father[x] == x ? x : father[x] = getfather(father[x]); } void up(int i){ mx[i] = max(mx[ls[i]], mx[rs[i]]); if (mx[i] == mx[ls[i]]) ret[i] = ret[ls[i]]; else ret[i] = ret[rs[i]]; } int build(int l, int r, int val){ int x = ++tot; ls[x] = rs[x] = mx[x] = ret[x] = 0; if (l == r){ mx[x] = 1; ret[x] = val; return x; } int mid = (l + r) >> 1; if (val <= mid) ls[x] = build(l, mid, val); else rs[x] = build(mid + 1, r, val); up(x); return x; } int Merge(int x, int y, int l, int r){ if (x == 0 || y == 0) return x + y; if (l == r){ mx[x] += mx[y]; return x; } int mid = (l + r) >> 1; ls[x] = Merge(ls[x], ls[y], l, mid); rs[x] = Merge(rs[x], rs[y], mid + 1, r); up(x); return x; } int main(){ scanf("%d", &T); while (T--){ tot = 0; scanf("%d%d", &n, &m); rep(i, 1, n) scanf("%d", c + i); rep(i, 1, n){ father[i] = i; v[i] = 0; f[i][0] = i; root[i] = build(1, n, c[i]); res[i] = ret[root[i]]; } id = n; rep(i, 1, m) e[i].scan(); sort(e + 1, e + m + 1); rep(i, 1, m){ int x = e[i].x, y = e[i].y, z = e[i].z; int fx = getfather(x), fy = getfather(y); if (fx ^ fy){ ++id; f[id][0] = id; father[id] = id; v[id] = z; father[fx] = father[fy] = id; f[fx][0] = f[fy][0] = id; root[id] = Merge(root[fx], root[fy], 1, n); res[id] = ret[root[id]]; } } rep(j, 1, 17){ rep(i, 1, id) f[i][j] = f[f[i][j - 1]][j - 1]; } printf("Case #%d:\n", ++ca); scanf("%d", &q); ans = 0; while (q--){ int x, w; scanf("%d%d", &x, &w); x ^= ans, w ^= ans; dec(i, 17, 0) if (v[f[x][i]] <= w) x = f[x][i]; printf("%d\n", ans = res[x]); } } return 0; }
Codeforces Gym 101194G Pandaria (2016 ACM-ICPC EC-Final G題, 並查集 + 線段樹合並)