TZOJ 4848 货车运输(最大生成树+倍增lca)

描述

A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入

第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。

接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。

接下来一行有一个整数 q,表示有 q 辆货车需要运货。

接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

输出

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

样例输入

4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3

样例输出

3
-1
3

提示

对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;

对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;

对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

题意

如上

题解

要使路径上的最小值尽可能大,跑一个最大生成树

然后在查询树上路径最小值的时候,可以跑一个倍增lca

查询u,v的最小值的时候,先找到u,v的公共祖先p,再求min(up的最小值,vp的最小值)

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 const int maxn=10005;
  5 const int maxm=50005;
  6 int deep[maxn],fa[maxn][20],dis[maxn][20],lg[maxn],vis[maxn],f[maxn],n,m;
  7 vector< pair<int,int> >G[maxn];
  8 struct edge
  9 {
 10     int u,v,w;
 11     bool operator<(const edge &D)const{
 12         return w>D.w;
 13     }
 14 }edges[maxm];
 15 void dfs(int u)
 16 {
 17     vis[u]=1;
 18     for(auto X:G[u])
 19     {
 20         int v=X.first;
 21         int w=X.second;
 22         if(vis[v])continue;
 23         fa[v][0]=u;
 24         dis[v][0]=w;
 25         deep[v]=deep[u]+1;
 26         dfs(v);
 27     }   
 28 }
 29 void RNQ()
 30 {
 31     for(int j=1;(1<<j)<=n;j++)
 32         for(int i=1;i<=n;i++)
 33             fa[i][j]=fa[fa[i][j-1]][j-1],
 34             dis[i][j]=min(dis[i][j-1],dis[fa[i][j-1]][j-1]);
 35 }
 36 int lca(int x,int y)
 37 {
 38     if(deep[x]<deep[y])swap(x,y);
 39     while(deep[x]>deep[y])x=fa[x][lg[deep[x]-deep[y]]-1];
 40     if(x==y)return x;
 41     for(int k=lg[deep[x]];k>=0;k--)
 42         if(fa[x][k]!=fa[y][k])
 43             x=fa[x][k],y=fa[y][k];
 44     return fa[x][0];
 45 }
 46 int find(int x)
 47 {
 48     return f[x]==x?x:f[x]=find(f[x]);
 49 }
 50 int query(int x,int y)
 51 {
 52     int ans=0x3f3f3f3f,t=deep[x]-deep[y];
 53     for(int i=0;i<=16;i++)
 54         if(t&(1<<i))
 55             ans=min(ans,dis[x][i]),
 56             x=fa[x][i];
 57     return ans;
 58 }
 59 void max_kruskal()
 60 {
 61     int cnt=0;
 62     sort(edges,edges+m);
 63     for(int i=0;i<m;i++)
 64     {
 65         int u=edges[i].u;
 66         int v=edges[i].v;
 67         int w=edges[i].w;
 68         int fu=find(u);
 69         int fv=find(v);
 70         if(fu!=fv)
 71         {
 72             G[u].push_back({v,w});
 73             G[v].push_back({u,w});
 74             f[fu]=fv;
 75             if(++cnt==n-1)break;
 76         }
 77     }
 78 }
 79 int main()
 80 {
 81     memset(dis,0x3f3f3f3f,sizeof dis);
 82     memset(vis,false,sizeof vis);
 83     int u,v,w,q;
 84     scanf("%d%d",&n,&m);
 85     for(int i=1;i<=n;i++)lg[i]=lg[i-1]+(1<<lg[i-1]==i),f[i]=i;
 86     for(int i=0;i<m;i++)
 87     {
 88         scanf("%d%d%d",&u,&v,&w);
 89         edges[i]={u,v,w};
 90     }
 91     max_kruskal();
 92     for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
 93     RNQ();
 94     scanf("%d",&q);
 95     for(int i=0;i<q;i++)
 96     {
 97         scanf("%d%d",&u,&v);
 98         if(find(u)!=find(v))printf("-1\n");
 99         else
100         {
101             int father=lca(u,v);
102             printf("%d\n",min(query(u,father),query(v,father)));
103         }
104     }
105     return 0;
106 }

posted on 2018-09-18 21:48  大桃桃  阅读(249)  评论(0)    收藏  举报

导航