标签:temp max bre || 生成 标记 printf include sync
我们先找出一棵最小生成树,
对于非树边来说, 答案就是两点路径上的最大值 - 1, 这个直接倍增就能处理。
对于树边来说, 就是非树边的路径经过这条边的最小值 - 1, 这个可以用并查集压缩路径 或者 更压st表一样的方式更新。
感觉就是没想到先扣出来一个最小生成树, 而是往克鲁斯卡尔的过程中想了。
#include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 2e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;} int n, m; vector<PII> G[N]; bool can[N]; int ans[N]; int pathMin[N]; struct Edge { int u, v, c, id; bool operator < (const Edge &rhs) const { return c < rhs.c; } } e[N]; int fa[N]; int getRoot(int x) { return fa[x] == x ? x : fa[x] = getRoot(fa[x]); } int pa[N][20], mx[N][20], depth[N]; void dfs(int u, int fa, int w) { depth[u] = depth[fa] + 1; pa[u][0] = fa; mx[u][0] = w; for(int i = 1; i < 20; i++) pa[u][i] = pa[pa[u][i - 1]][i - 1]; for(int i = 1; i < 20; i++) mx[u][i] = max(mx[u][i - 1], mx[pa[u][i - 1]][i - 1]); for(auto& e : G[u]) { if(e.se == fa ) continue; dfs(e.se, u, e.fi); } } int getMaxWei(int u, int v) { if(depth[u] < depth[v]) swap(u, v); int dis = depth[u] - depth[v]; int ans = 0; for(int i = 19; i >= 0; i--) if(dis >> i & 1) chkmax(ans, mx[u][i]), u = pa[u][i]; if(u == v) return ans; for(int i = 19; i >= 0; i--) { if(pa[u][i] != pa[v][i]) { chkmax(ans, mx[u][i]); chkmax(ans, mx[v][i]); u = pa[u][i]; v = pa[v][i]; } } chkmax(ans, mx[u][0]); chkmax(ans, mx[v][0]); return ans; } int getLca(int u, int v) { if(depth[u] < depth[v]) swap(u, v); int dis = depth[u] - depth[v]; for(int i = 19; i >= 0; i--) if(dis >> i & 1) u = pa[u][i]; if(u == v) return u; for(int i = 19; i >= 0; i--) if(pa[u][i] != pa[v][i]) u = pa[u][i], v = pa[v][i]; return pa[u][0]; } void gao(int u, int v, int c) { while(1) { u = getRoot(u); if(depth[u] <= depth[v]) break; pathMin[u] = c; int nex = getRoot(pa[u][0]); fa[u] = nex; u = nex; } } int main() { memset(pathMin, 0x3f, sizeof(pathMin)); scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= m; i++) { scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].c); e[i].id = i; } sort(e + 1, e + 1 + m); for(int i = 1; i <= m; i++) { int u = e[i].u, v = e[i].v, c = e[i].c, id = e[i].id; int x = getRoot(u); int y = getRoot(v); if(x != y) { can[i] = true; fa[y] = x; G[u].push_back(mk(c, v)); G[v].push_back(mk(c, u)); } } dfs(1, 0, 0); for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= m; i++) { if(can[i]) continue; int u = e[i].u, v = e[i].v, c = e[i].c, id = e[i].id; int lca = getLca(u, v); gao(u, lca, c); gao(v, lca, c); } for(int i = 1; i <= m; i++) { int u = e[i].u, v = e[i].v, c = e[i].c, id = e[i].id; if(!can[i]) { ans[id] = getMaxWei(u, v) - 1; } else { if(depth[u] < depth[v]) swap(u, v); ans[id] = pathMin[u] == inf ? -1 : pathMin[u] - 1; } } for(int i = 1; i <= m; i++) printf("%d%c", ans[i], " \n"[i == m]); return 0; } /* */
Codeforces 827D Best Edge Weight 倍增 + 并查集 || 倍增 + 压倍增标记 (看题解)
标签:temp max bre || 生成 标记 printf include sync
原文地址:https://www.cnblogs.com/CJLHY/p/10956883.html