BZOJ 3732: Network【最小生成树+LCA】
3732: Network
Time Limit: 10 Sec Memory Limit: 128 MB
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 < = 20,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
题解
这提要求我们求边长的最大值最小,所以我们需要满足两个条件,“最大值最小”很容易让人想到二分,但是这题显然不行,那么“最大值最小”还可以用最小生成树进行求解,正好适合这题,然后LCA一下就可以了。
贴上代码
#include<cstdio>
#include<algorithm>
#define MAXN 15005
using namespace std;
struct xcw{
int x,y,z;
bool operator <(const xcw b)const{return z<b.z;}
}a[2*MAXN];
int n,m,K,fa[MAXN],Dep[MAXN];
int tot,lnk[MAXN],nxt[2*MAXN],son[2*MAXN],W[2*MAXN];
int Fa[MAXN][30],F[MAXN][30];
int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
void Add(int x,int y,int z){son[++tot]=y;W[tot]=z;nxt[tot]=lnk[x];lnk[x]=tot;}
void Kruskal(){
int Now=0;
for(int i=1;i<=m;i++){
int x=get(a[i].x),y=get(a[i].y);
if(x^y){
fa[y]=x;
Add(a[i].x,a[i].y,a[i].z);Add(a[i].y,a[i].x,a[i].z);
if(++Now==n-1) return;
}
}
}
void DFS(int x,int Lst,int D){
Dep[x]=D;
for(int j=lnk[x];j;j=nxt[j])
if(son[j]^Lst) Fa[son[j]][0]=x,F[son[j]][0]=W[j],DFS(son[j],x,D+1);
}
void Rmq(){
for(int i=1;i<=n;i++)
for(int j=1;(1<<j)<n;j++) Fa[i][j]=-1;
for(int j=1;(1<<j)<n;j++)
for(int i=1,x;i<=n;i++)
if(Fa[i][j-1]^-1) x=Fa[i][j-1],F[i][j]=max(F[i][j-1],F[x][j-1]),Fa[i][j]=Fa[x][j-1];
}
int get(int p,int q){
if(Dep[p]<Dep[q]) swap(p,q);
int Log,sum=0;
for(Log=0;(1<<Log)<Dep[p];Log++);Log--;
for(int i=Log;i+1;i--)
if(Dep[Fa[p][i]]>=Dep[q]) sum=max(sum,F[p][i]),p=Fa[p][i];
if(p==q) return sum;
for(int i=Log;i+1;i--)
if(Fa[p][i]^-1&&Fa[p][i]^Fa[q][i])
sum=max(sum,F[p][i]),sum=max(sum,F[q][i]),p=Fa[p][i],q=Fa[q][i];
sum=max(sum,F[p][0]);sum=max(sum,F[q][0]);
return sum;
}
int main(){
// freopen("prob.in","r",stdin);
// freopen("prob.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
sort(a+1,a+1+m);
for(int i=1;i<=n;i++) fa[i]=i;
Kruskal();DFS(1,0,1);Rmq();
for(int i=1;i<=K;i++){
int x,y;scanf("%d%d",&x,&y);
printf("%d\n",get(x,y));
}
return 0;
}