P1967 货车运输

P1967 货车运输

思路:

    将边权从大到小排序,然后建立最大生成树,在新图上求两个点的lca即可

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <cctype>
  7 using namespace std;
  8 
  9 #define inf 0x7f7f7f7f
 10 #define LL long long
 11 #define res register int
 12 inline int read()
 13 {
 14     int x(0),f(1); char ch;
 15     while(!isdigit(ch=getchar())) if(ch=='-') f=-1;
 16     while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
 17     return f*x;
 18 }
 19 int n,m;
 20 const int N=500000+5;
 21 int head[N],nxt[N<<1],ver[N<<1],edge[N<<1],tot;
 22 struct E{
 23     int u,v,w;
 24 }e[N];
 25 int vis[N],fa[N],d[N];
 26 int f[N][22],dis[N][22];
 27 
 28 //inline int min(int a,int b){return a<b?a:b;}
 29 inline bool cmp(E a,E b) {return a.w>b.w;}
 30 inline void add(int x,int y,int z) {
 31     ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot; edge[tot]=z;
 32     ver[++tot]=x; nxt[tot]=head[y]; head[y]=tot; edge[tot]=z;
 33 }    
 34 //inline void swap(int &x,int &y) {int tmp=x; x=y; y=tmp;}
 35 inline int get(int x) {
 36     if(x==fa[x]) return x; return fa[x]=get(fa[x]);
 37 }
 38 
 39 inline void Kruskal()
 40 {
 41     sort(e+1,e+m+1,cmp);
 42     for(res i=1 ; i<=n ; i++) fa[i]=i;
 43     for(res i=1 ; i<=m ; i++)
 44     {
 45         int x=get(e[i].u),y=get(e[i].v),z=e[i].w;
 46         if(x==y) continue;
 47         fa[x]=y;
 48         add(x,y,z);
 49     }
 50 }
 51 
 52 void dfs(int x)
 53 {
 54     vis[x]=1;
 55     for(res i(head[x]) ; i ; i=nxt[i])
 56     {
 57         int y=ver[i]; 
 58         if(vis[y]) continue;
 59         f[y][0]=x; dis[y][0]=edge[i];
 60 //        printf("dis %d",dis[y][0]);
 61         d[y]=d[x]+1;    dfs(y);
 62     }
 63 }
 64 
 65 inline int lca(int x,int y)
 66 {
 67     if(get(x)!=get(y)) return -1;
 68     if(d[x]<d[y]) swap(x,y);
 69     int ans=inf;
 70     for(res i=20 ; i>=0 ; i--)
 71         if(d[f[x][i]]>=d[y])
 72         {
 73             ans=min(ans,dis[x][i]);    
 74             x=f[x][i];
 75         } 
 76     if(x==y) return ans;
 77     for(res i=20 ; i>=0 ; i--)
 78         if(f[x][i]!=f[y][i])
 79         {
 80             ans=min(ans,dis[x][i]);
 81             ans=min(ans,dis[y][i]);
 82             x=f[x][i],y=f[y][i];
 83         }
 84     ans=min(ans,dis[x][0]);
 85     ans=min(ans,dis[y][0]);
 86     return ans;
 87 }
 88 
 89 
 90 int main()
 91 {
 92 //    freopen("in.txt","r",stdin);
 93     n=read(); m=read();
 94     for(res i=1 ; i<=m ; i++) 
 95         e[i].u=read(), e[i].v=read(),e[i].w=read();
 96     Kruskal();
 97     for(res i=1 ; i<=n ; i++)
 98     {
 99         if(!vis[i]) 
100         {
101             d[i]=1; dfs(i);
102             f[i][0]=i; dis[i][0]=inf;    
103         }
104     }
105     //注意顺序
106     for(int i=1; i<=20; i++)
107         for(int j=1; j<=n; j++){
108             f[j][i]=f[f[j][i-1]][i-1]; 
109             dis[j][i]=min(dis[j][i-1], dis[f[j][i-1]][i-1]);
110         }
111     int q=read();
112     for(res i=1 ; i<=q ; i++)
113     {
114         int x=read(),y=read();
115         printf("%d\n",lca(x,y));
116     }
117     return 0;
118 }
View Code

 

转载于:https://www.cnblogs.com/wmq12138/p/10380953.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值