bzoj 3732: Network 树上两点边权最值
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; }
既然选择了远方,就要风雨兼程~
posted on 2017-08-18 22:24 stupid_one 阅读(306) 评论(0) 编辑 收藏 举报