bzoj3732 -- 最小生成树+倍增

显然使A到B的最长边最小的路径一定在最小生成树上,否则一定可以使生成树更小。

求出原图的最小生成树,然后用倍增求路径上最大值就可以了。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 #define N 15010
 7 #define S 15
 8 struct Edge{
 9     int f,t,nx,w;
10     Edge(){}
11     Edge(int f,int t,int w):f(f),t(t),w(w){}
12     bool operator < (Edge a)const{
13         return w>a.w;
14     }
15 }e[N<<1],tmp;
16 priority_queue<Edge>Q;
17 int d[N],i,j,k,x,y,z,n,m,Num,h[N],f[N][S],Max[N][S];
18 inline int _Max(int x,int y){return x<y?y:x;}
19 inline void Add(int x,int y,int z){
20     e[++Num].t=y;e[Num].w=z;e[Num].nx=h[x];h[x]=Num;
21 }
22 inline int Find(int x){return f[x][0]==x?x:f[x][0]=Find(f[x][0]);}
23 inline void Dfs(int x,int F){
24     f[x][0]=F;d[x]=d[F]+1;
25     for(int i=h[x];i;i=e[i].nx)
26     if(e[i].t!=F)Max[e[i].t][0]=e[i].w,Dfs(e[i].t,x);
27 }
28 inline int Query(int x,int y){
29     if(d[x]<d[y])swap(x,y);
30     int Ans=0;
31     for(int i=S-1;i>=0;i--)
32     if(d[f[x][i]]>=d[y])Ans=_Max(Ans,Max[x][i]),x=f[x][i];
33     if(x==y)return Ans;
34     for(int i=S-1;i>=0;i--)
35     if(f[x][i]!=f[y][i])Ans=_Max(Ans,_Max(Max[x][i],Max[y][i])),x=f[x][i],y=f[y][i];
36     return _Max(Ans,_Max(Max[x][0],Max[y][0]));
37 }
38 int main()
39 {
40     scanf("%d%d%d",&n,&m,&k);
41     for(i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&z),Q.push(Edge(x,y,z));
42     for(i=1;i<=n;i++)f[i][0]=i;
43     for(i=1;i<n;i++){
44         tmp=Q.top();Q.pop();
45         while(Find(tmp.f)==Find(tmp.t))tmp=Q.top(),Q.pop();
46         f[Find(tmp.f)][0]=Find(tmp.t);Add(tmp.f,tmp.t,tmp.w);Add(tmp.t,tmp.f,tmp.w);
47     }
48     Dfs(1,0);
49     for(j=1;j<S;j++)
50     for(i=1;i<=n;i++)
51     f[i][j]=f[f[i][j-1]][j-1],Max[i][j]=_Max(Max[i][j-1],Max[f[i][j-1]][j-1]);
52     while(k--){
53         scanf("%d%d",&x,&y);
54         printf("%d\n",Query(x,y));
55     }
56     return 0;
57 }
bzoj3732

 

posted @ 2017-03-19 08:49  gjghfd  阅读(127)  评论(0编辑  收藏  举报