20200713 T3 圖論
阿新 • • 發佈:2020-07-13
題目描述
\(\text{Tom}\) 熱愛出毒瘤題,但這次他似乎出了一個並不毒瘤的題。
給定一張 \(N\) 個點 \(M\) 條無向邊的圖,每條邊有邊權 \(w\)。定義一個連通塊的大小為該連通塊內所有邊權的和。
然後進行 \(K\) 組詢問。每次詢問在由所有邊權不超過 \(X_i\) 的邊構成的新的生成子圖中連通塊的大小的最大值。
輸入格式
第 \(1\) 行 \(3\) 個整數 \(n,m,k\) 表示圖有 \(n\) 個點,\(m\) 條邊。有 k 組詢問。
第 \(2\) 行到第 \(m + 1\) 行每行三個正整數 \(u,v,w,\)表示點 \(u\) 和點 \(v\) 之間有一條邊權為 \(w\)
第 \(m + 1\) 行到第 \(m + k\) 行每行一個整數 \(x\),表示在這次詢問中,只能使用邊權不超過 \(w\) 的邊。
可能存在重邊,但不存在自環。
輸出格式
\(K\) 行,對於每組詢問輸出一次答案。
樣例
input1
5 5 3
1 2 5
2 3 6
3 4 4
3 5 2
4 5 3
7
5
3
output1
20
9
5
資料規模和限制
對於全部測試資料,滿足 \(N,M,K \leq 100000\),\(W \leq1000\)
測試點 | N | M | K |
---|---|---|---|
\(1\) | \(\leq 10\) | \(\leq 10\) | \(\leq 10\) |
\(2 \sim 3\) |
\(\leq 1000\) | \(\leq 1000\) | \(\leq 1000\) |
\(4 \sim 5\) | \(\leq 1000\) | \(\leq 1000\) | \(\leq 100000\) |
\(6 \sim 10\) | \(\leq 100000\) | \(\leq 100000\) | \(\leq 100000\) |
思路
並查集。
將詢問離線。從對邊權的限制由小到大處理,這樣就轉化成了不斷往一個圖中加邊,詢問你加了多少遍之後最大的連通塊的大小。
Code
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> #define MAXN 100001 typedef int ll; inline void read(ll &T) { ll x = 0; bool f = 0; char c = getchar(); while(c < '0' || c > '9') { if (c == '-') f = !f; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } T = f ? -x : x; } inline void write(ll x) { if (x < 0) putchar('-'), write(-x); else { if (x / 10) write(x / 10); putchar(x % 10 + '0'); } } int n, m, k; ll ub[MAXN], ans[MAXN]; int fa[MAXN], size[MAXN]; struct P { int u, v; ll w; friend bool operator < (P x, P y) { return x.w < y.w; } }a[MAXN]; struct query { int w, num; friend bool operator < (query x, query y) { return x.w < y.w; } }q[MAXN]; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } void Union(int x, int y) { if (x > y) std::swap(x, y); fa[y] = x; } ll max(ll a, ll b) { return a > b ? a : b; } int main() { //freopen("Graph.in", "r", stdin); //freopen("Graph.out", "w", stdout); scanf("%d %d %d", &n, &m, &k); for (int i = 1; i <= n; ++i) fa[i] = i; for (int i = 1; i <= m; ++i) { scanf("%d %d", &a[i].u, &a[i].v); read(a[i].w); } std::sort(a + 1, a + m + 1); for (int i = 1; i <= k; ++i) { scanf("%d", &q[i].w); q[i].num = i; } std::sort(q + 1, q + k + 1); int now = 1; ll maxx = 0; for (int i = 1; i <= k; ++i) { while(q[i].w >= a[now].w && now <= m) { int rootx = find(a[now].u), rooty = find(a[now].v); if (rootx != rooty) Union(rootx, rooty); if (rootx < rooty) { ub[rootx] += a[now].w; ub[rootx] += ub[rooty]; ub[rooty] = 0; maxx = max(maxx, ub[rootx]); } else { ub[rooty] += a[now].w; if (rootx != rooty) { ub[rooty] += ub[rootx]; ub[rootx] = 0; } maxx = max(maxx, ub[rooty]); } ++now; } ans[q[i].num] = maxx; } for (int i = 1; i <= k; ++i) write(ans[i]), puts(""); fclose(stdin), fclose(stdout); return 0; }