標籤:std -- href 遞迴 main res ble lca 深度
http://www.lydsy.com/JudgeOnline/problem.php?id=3732
首先想到,要使得最長邊最短,應該盡量走最短的邊,在MST上。
然後像LCA那樣倍增娶個最大值
#include <bits/stdc++.h>#define IOS ios::sync_with_stdio(false)using namespace std;#define inf (0x3f3f3f3f)typedef long long int LL;const int maxn = 30000 + 20;struct Edge { int u, v, w, tonext; bool operator < (const struct Edge & rhs) const { return w < rhs.w; }} e[maxn], t[maxn];int first[maxn], num;void addEdge(int u, int v, int w) { e[num].u = u, e[num].v = v, e[num].w = w, e[num].tonext = first[u]; first[u] = num++;}int tfa[maxn];int tofind(int u) { if (tfa[u] == u) return u; else return tfa[u] = tofind(tfa[u]);}const int need = 20;int mx[maxn][25];int ansc[maxn][25], deep[maxn], fa[maxn]; //所有只需初始值,不需要初始化。void init_LCA(int cur) { //1 << 20就有1048576(1e6)了。 ansc[cur][0] = fa[cur]; //跳1步,那麼祖先就是爸爸 if (cur != 1) { for (int i = first[fa[cur]]; ~i; i = e[i].tonext) { int v = e[i].v; if (v == cur) { mx[cur][0] = e[i].w; break; } } } int haha = mx[cur][0]; for (int i = 1; i <= need; ++i) { //倍增思路,遞迴處理 ansc[cur][i] = ansc[ansc[cur][i - 1]][i - 1]; mx[cur][i] = mx[ansc[cur][i - 1]][i - 1]; mx[cur][i] = max(mx[cur][i], haha); haha = max(haha, mx[cur][i]); //上到極限的時候需要取個路經的最大值。 } for (int i = first[cur]; ~i; i = e[i].tonext) { int v = e[i].v; if (v == fa[cur]) continue; fa[v] = cur; deep[v] = deep[cur] + 1; init_LCA(v); }}int LCA(int x, int y) { int res = 0; if (deep[x] < deep[y]) swap(x, y); //需要x是最深的 for (int i = need; i >= 0; --i) { //從大到小枚舉,因為小的更靈活 if (deep[ansc[x][i]] >= deep[y]) { //深度相同,走進去就對了。就是要去到相等。 res = max(res, mx[x][i]); x = ansc[x][i]; } } if (x == y) return res; for (int i = need; i >= 0; --i) { if (ansc[x][i] != ansc[y][i]) { //走到第一個不等的地方, res = max(res, mx[x][i]); res = max(res, mx[y][i]); x = ansc[x][i]; y = ansc[y][i]; } } res = max(res, mx[x][0]); res = max(res, mx[y][0]); return res; //再跳一步就是答案}void work() { num = 0; memset(first, -1, sizeof first); int n, m, k; scanf("%d%d%d", &n, &m, &k); for (int i = 1; i <= n; ++i) tfa[i] = i; for (int i = 1; i <= m; ++i) { scanf("%d%d%d", &t[i].u, &t[i].v, &t[i].w); } sort(t + 1, t + 1 + m); int sel = 0; for (int i = 1; i <= m; ++i) { if (sel == n - 1) break; int x = tofind(t[i].u), y = tofind(t[i].v); if (x == y) continue; sel++; tfa[y] = x; addEdge(t[i].u, t[i].v, t[i].w); addEdge(t[i].v, t[i].u, t[i].w); } fa[1] = 1, deep[1] = 0; init_LCA(1);// printf("%d\n", mx[2][1]); for (int i = 1; i <= k; ++i) { int u, v; scanf("%d%d", &u, &v); printf("%d\n", LCA(u, v)); }}int main() {#ifdef local freopen("data.txt", "r", stdin);// freopen("data.txt", "w", stdout);#endif work(); return 0;}
View Code
bzoj 3732: Network 樹上兩點邊權最值