欢迎来到蒟蒻mqd的博客

BZOJ 3732: Network 最小生成树 倍增

3732: Network

题目连接:

http://www.lydsy.com/JudgeOnline/problem.php?id=3732

Description

给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。
图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).

现在有 K个询问 (1 < = K < = 15,000)。
每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Input

第一行: N, M, K。
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Output

对每个询问,输出最长的边最小值是多少。

Sample Input

6 6 8

1 2 5

2 3 4

3 4 3

1 4 8

2 5 7

4 6 2

1 2

1 3

1 4

2 3

2 4

5 1

6 2

6 1

Sample Output

5

5

5

4

4

7

4

5

Hint

1 <= N <= 15,000

1 <= M <= 30,000

1 <= d_j <= 1,000,000,000

1 <= K <= 15,000

题意

题解:

我一开始竟然在想一个好傻的问题:生成一棵最长边最小的树,可不可以保证任意两点之间最长边最小。(最小生成树没学好的结果)

这题比较裸,先生成最小生成树,然后倍增求两点路径最长边。

当然树链剖分也行,感觉树剖也挺容易打的。

Debug

1.n,m混用,导致最小生成树写错了。

2.数组开小了,点和边应该分开开数组。

3.倍增时,如果调整高度相同时,如果x==y,要直接返回答案。

代码

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long
  4 #define N 40050
  5 int n,m,dp[N],mx[N][15],fu[N][15],mm[N];
  6 int tot,last[N];
  7 struct Edge
  8 {
  9     int from,to,val,s;
 10     bool operator <(const Edge&b)const 
 11         {return val<b.val;}
 12 }a[N],edges[N<<1];
 13 template<typename T>void read(T&x)
 14 {
 15     ll k=0; char c=getchar();
 16     x=0;
 17     while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
 18     if (c==EOF)exit(0);
 19     while(isdigit(c))x=x*10+c-'0',c=getchar();
 20     x=k?-x:x;
 21 }
 22 void read_char(char &c)
 23 {while(!isalpha(c=getchar())&&c!=EOF);}
 24 void AddEdge(int x,int y,int z)
 25     {
 26         edges[++tot]=Edge{x,y,z,last[x]};
 27         last[x]=tot;
 28     }
 29 int gf(int x,int *fa)
 30 {
 31     if(x==fa[x])return x;
 32     return fa[x]=gf(fa[x],fa);
 33 }
 34 void MST(Edge *edges)
 35 {
 36     static Edge a[N];
 37     static int fa[N];
 38     for(int i=1;i<=m;i++)a[i]=edges[i];
 39     for(int i=1;i<=n;i++)fa[i]=i;//
 40     sort(a+1,a+m+1);
 41     int num=0;
 42     for(int i=1;i<=m;i++)//
 43     {
 44         int fx=gf(a[i].from,fa),fy=gf(a[i].to,fa);
 45         if (fx==fy)continue;
 46         AddEdge(a[i].from,a[i].to,a[i].val);
 47         AddEdge(a[i].to,a[i].from,a[i].val);
 48         fa[fx]=fy;
 49         if (++num==n-1)break;
 50     }
 51 }
 52 void dfs(int x,int pre)
 53 {
 54     fu[x][0]=pre;
 55     dp[x]=dp[pre]+1;
 56     for(int i=last[x];i;i=edges[i].s)
 57     {
 58         Edge &e=edges[i];
 59         if (e.to==pre)continue;
 60         mx[e.to][0]=e.val;
 61         dfs(e.to,x);
 62     }
 63 }
 64 void init_ST()
 65 {
 66     for(int i=2;i<=n;i++)mm[i]=mm[i>>1]+1;
 67     for(int i=1;i<=14;i++)
 68         for(int j=1;j<=n;j++)//
 69         {
 70             fu[j][i]=fu[fu[j][i-1]][i-1];
 71             mx[j][i]=max(mx[j][i-1],mx[fu[j][i-1]][i-1]);
 72         }
 73 }
 74 int GetLca(int x,int y)
 75 {
 76     int ans=0;
 77     if (dp[x]<dp[y])swap(x,y);
 78     int k=mm[dp[x]-dp[y]];//
 79     for(int i=k;i>=0;i--)
 80         if (dp[fu[x][i]]>=dp[y])
 81         {
 82             ans=max(ans,mx[x][i]);
 83             x=fu[x][i];
 84         }
 85     if (x==y)return ans;//
 86     k=mm[dp[x]-1];
 87     for(int i=k;i>=0;i--)
 88         if (fu[x][i]!=fu[y][i])
 89         {
 90             ans=max(ans,mx[x][i]);
 91             ans=max(ans,mx[y][i]);
 92             x=fu[x][i];
 93             y=fu[y][i];
 94         }
 95     ans=max(ans,mx[x][0]);
 96     ans=max(ans,mx[y][0]);
 97     return ans;
 98 }
 99 int main()
100 {
101 #ifndef ONLINE_JUDGE
102     freopen("aa.in","r",stdin);
103 #endif
104     int q;
105     read(n); read(m); read(q);
106     for(int i=1;i<=m;i++)
107     {
108         int x,y,z;
109         read(x); read(y); read(z);
110         a[i]=Edge{x,y,z,0};
111     }
112     MST(a);
113     dfs(1,0);
114     init_ST();
115     for(int i=1;i<=q;i++)
116     {
117         int x,y;
118         read(x); read(y);
119         printf("%d\n",GetLca(x,y));
120     }
121 }
View Code

 

posted @ 2019-05-09 12:09  mmqqdd  阅读(147)  评论(0编辑  收藏  举报