【洛谷P1697】货车运输

首先,对于所有从x能到达y的路径中,限重越大越好 

因此我们用Kruskal最大生成树得到一片森林(不一定都联通)

之后dfs维护森林的深度和LCA的预处理limit[x][0](x向上跳2^i步的边权最小值) 

对于每个询问,求x和y到lca的边权最小值即可

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 #define N 10010
  6 #define M 100010
  7 #define INF 100000000 
  8 struct fx{
  9     int to,w,from,next;
 10     
 11 }e[M],t[M];
 12 int size,n,m,q,head[M],maxl[N],father[N];
 13 int fa[N][25],limit[N][25],deep[N],vis[N];
 14 void uni(int x,int y,int z){
 15     size++;
 16     e[size].to=y;
 17     e[size].from=x;
 18     e[size].w=z;
 19 }
 20 void Uni(int x,int y,int z){
 21     size++;
 22     t[size].next=head[x];
 23     head[x]=size;
 24     t[size].to=y;
 25     t[size].from=x;
 26     t[size].w=z;
 27 }
 28 bool cmp(fx a,fx b){
 29     return a.w>b.w;
 30 }
 31 int find(int x){
 32     if (father[x]!=x) father[x]=find(father[x]);
 33     return father[x];
 34 }
 35 void swap(int &x,int &y){
 36     int tmp;
 37     tmp=x;
 38     x=y;
 39     y=tmp;
 40 }
 41 void kruskal(){
 42     int x,y,r1,r2,cnt;
 43     for (int i=1;i<=n;i++)
 44         father[i]=i;
 45     sort(e+1,e+m+1,cmp);
 46     size=0;cnt=n;
 47     for (int p=1;p<=m&&cnt>1;p++){
 48         x=e[p].from;
 49         y=e[p].to;
 50         r1=find(x);
 51         r2=find(y);
 52         if (r1!=r2){
 53             father[r1]=r2;
 54             cnt--;
 55             Uni(x,y,e[p].w);
 56             Uni(y,x,e[p].w);
 57         }
 58     }
 59 }
 60 void dfs(int x,int xx){
 61     vis[x]=1;
 62     fa[x][0]=xx;
 63     for (int k=head[x];k;k=t[k].next){
 64         int y=t[k].to;
 65         if (y==xx) continue;
 66         deep[y]=deep[x]+1;
 67         limit[y][0]=t[k].w;
 68         dfs(y,x);
 69     }
 70 }
 71 void Limit(){
 72     for (int j=1;j<=20;j++)
 73         for (int i=1;i<=n;i++){
 74             limit[i][j]=min(limit[fa[i][j-1]][j-1],limit[i][j-1]);
 75             fa[i][j]=fa[fa[i][j-1]][j-1];
 76         }
 77 }
 78 int LCA(int x,int y){
 79     int d,minl=INF;
 80     if (deep[x]<deep[y])
 81         swap(x,y);
 82     d=deep[x]-deep[y];
 83     for (int i=0;i<=20;i++)
 84         if ((1<<i)&d) {
 85             minl=min(minl,min(limit[x][i],limit[x][0]));
 86             x=fa[x][i];
 87         }
 88     if (x==y) return minl;//相等则不需向上跳   
 89     for (int i=20;i>=0;i--)
 90         if (fa[x][i]!=fa[y][i]){
 91             minl=min(minl,min(limit[x][i],limit[y][i]));
 92             x=fa[x][i];
 93             y=fa[y][i];
 94         }
 95     minl=min(minl,min(limit[x][0],limit[y][0]));
 96     return minl;
 97 }
 98 int main(){
 99     int x,y,z,r1,r2;
100     size=0;
101     scanf("%d %d",&n,&m);
102     for (int i=1;i<=m;i++){
103         scanf("%d %d %d",&x,&y,&z);
104         uni(x,y,z);
105     }
106     kruskal();
107     for (int i=1;i<=n;i++) 
108         if (!vis[i]){
109             deep[i]=1;
110             dfs(i,0);//森林  
111         }
112     Limit();
113     scanf("%d",&q);
114     for (int i=1;i<=q;i++){
115         scanf("%d %d",&x,&y);
116         r1=find(x);
117         r2=find(y);
118         if (r1!=r2) printf("-1\n");
119         else printf("%d\n",LCA(x,y));
120     }
121     return 0;
122 }
STD

 

转载于:https://www.cnblogs.com/Absolute-Zero/p/5947460.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值