NOIP 2013 提高组 洛谷P1967 货车运输 (Kruskal重构树)
题目:
A 国有 nn 座城市,编号从 11 到 nn,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
对于每一组询问,相当于求点x到点y中所有路径中最小边权的最大值,这样就是货车的最大载重。
那么这显然可以用Kruskal重构树来解决,将重构树建成大根堆,就可以求最大边权的最小值;同理,小根堆就是最小边权的最大值。
那么做这道题就是重构树的模板题了。复杂度O(q logn)。
1 #include2 using namespace std; 3 const int N=2e5+10; 4 struct edge{ 5 int u,v,w; 6 bool operator < (const edge &x){ 7 return w>x.w; //小根堆 8 } 9 }e[N]; 10 vector<int> g[N]; 11 int n,m,q,cnt,fa[N],vis[N],val[N],d[N],f[N][30]; 12 int find(int x){ 13 return fa[x]==x?fa[x]:fa[x]=find(fa[x]); 14 } 15 16 void kruskal(){ 17 sort(e+1,e+m+1); 18 for(int i=1;i<=n;i++) fa[i]=i; 19 for(int i=1;i<=m;i++){ 20 int fu=find(e[i].u),fv=find(e[i].v); 21 if(fu!=fv){ 22 val[++cnt]=e[i].w; 23 fa[cnt]=fa[fu]=fa[fv]=cnt; 24 g[cnt].push_back(fu); 25 g[cnt].push_back(fv); 26 g[fu].push_back(cnt); 27 g[fv].push_back(cnt); 28 } 29 } 30 } 31 32 void dfs(int u,int fa){ 33 d[u]=d[fa]+1,f[u][0]=fa,vis[u]=1; 34 for(int i=1;(1<) 35 f[u][i]=f[f[u][i-1]][i-1]; 36 for(int i=0;i ){ 37 int v=g[u][i]; 38 if(v!=fa) dfs(v,u); 39 } 40 } 41 42 int lca(int x,int y){ 43 if(d[x]<d[y]) swap(x,y); 44 for(int i=25;i>=0;i--) 45 if(d[f[x][i]]>=d[y]) x=f[x][i]; 46 if(x==y) return x; 47 for(int i=25;i>=0;i--) 48 if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 49 return f[x][0]; 50 } 51 52 int main(){ 53 scanf("%d%d",&n,&m); 54 cnt=n; 55 for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 56 kruskal(); 57 for(int i=1;i<=cnt;i++){//注意图可能是个森林,不要漏掉 58 if(!vis[i]){ 59 int f=find(i); 60 dfs(f,0); 61 } 62 } 63 scanf("%d",&q); 64 while(q--){ 65 int u,v; 66 scanf("%d%d",&u,&v); 67 if(find(u)!=find(v)) cout<<-1<<endl; 68 else cout< endl; 69 } 70 return 0; 71 }