【NOIP2013/Codevs3287】货车运输-最小生成树(大)-树上倍增
https://www.luogu.org/problemnew/show/P1967
由题可知,我们走的路的边应尽可能大,所以通过$kruscal$建最大生成树的图,再树上倍增,注意可能有多棵树;
#include <bits/stdc++.h> #define read read() #define up(i,l,r) for(register int i = (l);i <= (r);i++) #define down(i,l,r) for(register int i = (l);i >= (r);i--) #define traversal_vedge(i) for(register int i = head[u]; i ;i = e[i].nxt) #define ll long long using namespace std; int read { int x = 0, f = 1; char ch = getchar(); while(ch < 48 || ch > 57) {if(ch == '-')f = -1; ch = getchar();} while(ch >=48 && ch <=57) {x = 10 * x + ch - 48;ch = getchar();} return x * f; } const int N = 1e4+5,M = 5e5+5,inf = 0x3f3f3f3f; int n,m,q,f[N]; struct kedge{ int u,v,limit; bool operator < (const kedge &x) const{ return limit > x.limit; } }ke[M<<1]; struct edge{ int v,limit,nxt; }e[M<<1];int tot,head[N]; void build_tree(int u,int v,int w) {e[++tot] = (edge){v,w,head[u]}; head[u] = tot;} //----------------------------------------------------------------- int find(int i) {if(f[i] == i) return i;f[i] = find(f[i]);return f[i]; } void kruscal(){ sort(ke+1,ke+m+1); up(i,1,n) f[i] = i; int cnt = 0; up(i,1,m) { if(cnt == n-1) break; if(find(ke[i].u) != find(ke[i].v)) { f[f[ke[i].u]] = f[ke[i].v]; cnt++; build_tree(ke[i].u,ke[i].v,ke[i].limit); build_tree(ke[i].v,ke[i].u,ke[i].limit);//debug ke[i].u -> ke[i].v; } else continue; } } //----------------------------------------------------------------------- int fa[N][15],mine[N][15],dep[N],vis[N];//debug 15 ->14 void dfs(int u,int f,int w){ vis[u] = 1; dep[u] = dep[f] + 1; fa[u][0] = f; mine[u][0] = w; for(int i = 1; (1<<i) <= dep[u]; i++) { fa[u][i] = fa[fa[u][i-1]][i-1]; mine[u][i] = min(mine[u][i-1],mine[fa[u][i-1]][i-1]); } traversal_vedge(i) { int v = e[i].v; if(v == f) continue; dfs(v,u,e[i].limit); } } /*int LCA(int x,int y){ if(dep[x] < dep[y]) swap(x,y); down(i,14,0) { if(dep[fa[x][i]] >= dep[y]) x = fa[x][i]; } if(x == y) return x; down(i,14,0) { if(fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } } return fa[x][0]; }*/ //----------------------------------------------------------------- int query(int x,int y) { int ans = inf; if(dep[x] < dep[y]) swap(x,y); down(i,14,0) { if(dep[fa[x][i]] >= dep[y]) { ans = min(ans,mine[x][i]); x = fa[x][i]; } } if(x == y) return ans; down(i,14,0) { if(fa[x][i] != fa[y][i]) { ans = min(ans,min(mine[x][i],mine[y][i])); x = fa[x][i]; y = fa[y][i]; } } ans = min(ans,min(mine[x][0],mine[y][0])); return ans; } /*int query(int x,int lca){ //if(x == lca) return 0x3f3f3f3f; int i = 0; while(dep[fa[x][i]] > dep[lca] ) i++; return mine[x][i]; }*/ void work(){ kruscal(); memset(mine,0x3f,sizeof(mine)); //debug 未考虑多棵树 up(i,1,n) { if(!vis[i]) dfs(i,0,inf); } q = read; while(q--) { int x = read, y = read; if(find(x) != find(y)) { printf("-1\n"); continue; } //int lca = LCA(x,y); //ans = min(query(x,lca),query(y,lca)); printf("%d\n",query(x,y)); } } void readdata() { n = read; m = read; up(i,1,m) { ke[i].u = read; ke[i].v = read; ke[i].limit = read; } } int main() { freopen("input21.txt","r",stdin); //freopen("output21.out","w",stdout); readdata(); work(); return 0; }
最开始的写法之所以是错误的,是因为会多求一段,而我们只需要求到LCA就行;