【upc】小Y的图 | 树上倍增、最小生成树

问题 B: 小Y的图

时间限制: 1 Sec  内存限制: 256 MB
提交 状态

题目描述

小Y有一个n个点的无向图,图中的每个点从1到n标号。图中还有m条边,每条边有一个长度。
小Y有Q个询问,每次询问两个点所有路径中,最长的边最小值是多少,若这两个点之间没有任何路径,输出 -1。

输入

第一行三个整数n、m和Q。
接下来m行每行三个整数x、y、z(1≤x,y≤n,1≤z≤1000000),表示有一条连接x和y长度为z的边。
接下来Q行每行两个整数x、y(x≤y),表示一组询问。

输出

Q行每行一个整数,表示一组询问的答案。

样例输入 Copy

5 5 4
1 2 3
1 3 2
3 2 1
1 4 5
2 4 4
1 2
1 4
3 5
2 4

样例输出 Copy

2
4
-1
4

题目大意:

中文题意

题目思路:

其实之前,一直想找一个这种题..

刚好这题长我思路上了..

首先,最关键的就是题目中的最长的边的最小值

考虑最长边的最小值,那么最小生成树就出现了

可以想到把图全部退化最小生成树之后,任意两点之间的路径的最大值都是最优的

可以瞎证明一下:假设当前边(u,v)增加之后,使得u,v联通,那么如果不是最小生成树边,说明该边权比最小生成树上的边大,那么路径上的最大值就会增大

所以我们可以把图退化为最小生成树

之后就是询问树上任意两点的最大值

这个询问的话,就比较好处理了,点分治、整体二分、倍增都可以解决

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int Maxn=2e7+10;
const int maxn =3e5+10;
const int mod=1e9+9;
const int Mod = 1e9+7;
///const double eps=1e-10;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
vector< pair<int,int> >v[maxn];
int pre[maxn];
int f[maxn][20],Max[maxn][20];
int vis[maxn];
int Find(int x){
    return pre[x] == x?x:pre[x] = Find(pre[x]);
}
struct Edge{
    ll x,y,w;
}q[maxn];
bool cmp(Edge a,Edge b){
    return a.w < b.w;
}
int deep[maxn];
void dfs(int u,int fa,ll w)
{
    deep[u] = deep[fa]+1;
    f[u][0] = fa;
    Max[u][0] = w;
    for(int k=1;k<=19;k++) f[u][k] = f[f[u][k-1]][k-1];
    for(int k=1;k<=19;k++) Max[u][k] = max(Max[u][k-1],Max[f[u][k-1]][k-1]);
    for(auto x:v[u]){
        if(x.first == fa) continue;
        dfs(x.first,u,x.second);
    }
}
ll LCA(int u,int v)
{
    ll res = 0;
    if(deep[u]<deep[v]) swap(u,v);//保持u比v深
    for(int i=19;i>=0;i--){
        if(deep[f[u][i]]>=deep[v]){
            res = max(res,Max[u][i]*1ll);
            u=f[u][i];
        }
    }
    if(u==v) return res;
    for(int i=19;i>=0;i--){
        if(f[u][i]!=f[v][i]){
            res = max(res,Max[u][i]*1ll);
            res = max(res,Max[v][i]*1ll);
            u=f[u][i];
            v=f[v][i];
        }
    }
    return max(res,max(Max[u][0],Max[v][0])*1ll);
}
int main()
{
    read(n);read(m);read(p);
    for(int i=1;i<=n;i++) pre[i] = i;
    for(int i=1;i<=m;i++){
        read(q[i].x);
        read(q[i].y);
        read(q[i].w);
    }
    sort(q+1,q+1+m,cmp);
    for(int i=1;i<=m;i++){
        int dx = Find(q[i].x),dy = Find(q[i].y);
        if(dx != dy){
            v[q[i].x].push_back({q[i].y,q[i].w});
            v[q[i].y].push_back({q[i].x,q[i].w});
            pre[dx] = dy;
        }
    }
    for(int i=1;i<=n;i++){
        if(!deep[i])
            dfs(i,i,-1);
    }
    for(int i=1;i<=p;i++){
        ll x,y;read(x);read(y);
        if(Find(x)!=Find(y)) printf("-1\n");
        else printf("%lld\n",LCA(x,y));
    }
    return 0;
}
/**
1 1 5
1 2 4
1 3 3
2 2 3
**/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/107565521