HYSBZ - 3732 最小生成树+倍增Lca

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

码了一个星期终于过了这一题。(渣是原罪...)
最小生成树+倍增lca 
思路不难,但这是我第一次写lca的题目。下面一步步来解释这题。
题意:给你m条无向边,有k个查询,问从a到b所有路径上的最长边的最小值。
首先,从a到b所有路径上的最长边的最小值所对应的边一定在最小生成树上。
为什么?
现在来回忆一下Kru的做法。把所有边从小到大排序,接着从小到大使用这些边去联通每个点,当使用一条边x时,若x的两个端点在此之前已经联通,则说明这两个点在此之前已经被更短的边联通。可以想象,最小生成树上每两个点都是被最短的边联通的。即当两个点联通时的最长边不可能更小。
所以,现在问题转化为从a到b的在最小生成树上的路径的最长边是多少。
可知从a到b的最长边等于max(a->最近公共祖先c的最长边,b->c的最长边),即题目转化为lca问题。
至此,思路就很明确了。先构建最小生成树,再寻找两个点的最近公共祖先。
本蒟蒻用倍增lca寻找最近公共祖先,关于倍增lca的解释可以看以下博客( https://riteme.github.io/blog/2016-2-1/lca.html)。
我们设mx[i][j]表示点i到fa[i][j]的最长边,与fa[i][j]=fa[fa[i][j-1]][j-1]相似mx[i][j]=max(mx[i][j-1],mx[fa[i][j-1]][j-1]),即点i到fa[i][j]的最长边等于点i到fa[i][j-1]的最长边与点u(fa[i][j-1])到点fa[u][j-1]的最长边的最大值。(如图)

HYSBZ - 3732 最小生成树+倍增Lca_第1张图片

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long LL;
typedef pair pii;
const int maxn=3e4+20;
const int maxm=2700+10;
const int maxb=25;
const int mod=1e9+7;
const int inf=1e9+7;
const double infD=1000000007.0;
const double eps=0.00000001;

typedef struct Edge
{
    int x,y,w;
    Edge() {}
    Edge(int _x,int _y,int _w)
    {
        x=_x;
        y=_y;
        w=_w;
    }
    bool operator <(const struct Edge &r)const
    {
        return w G[maxn];
bool vis[maxn];
int deep[maxn],fa[maxn][maxb],mx[maxn][maxb];

int Find(int x)
{
    if(p[x]==x) return x;
    else return p[x]=Find(p[x]);
}

void Kru()
{
    for(int i=1; i<=n; i++) p[i]=i,G[i].clear();
    sort(e,e+m);
    int cnt=0;
    for(int i=0; i=0; i--)
    {
        if(deep[fa[u][i]]>=deep[v])
        {
            ans=max(ans,mx[u][i]);
            u=fa[u][i];
        }
    }
    if(u==v) return ans;
    for(int i=maxb-1; i>=0; i--)
    {
        if(fa[u][i]!=fa[v][i])
        {
            ans=max(ans,mx[u][i]);
            ans=max(ans,mx[v][i]);
            u=fa[u][i];
            v=fa[v][i];
        }
    }
    ans=max(ans,mx[u][0]);
    ans=max(ans,mx[v][0]);
    return ans;
}

void work()
{
    for(int i=0; i

后记:

这道题听师兄说是可以直接构造出最小生成树,构造的时候和并查集一样,按秩合并,就能保证树高是logn的,就不用写倍增lca了。但是本蒟蒻实在是太渣了,写了很久都还是TLE,有兴趣的大佬可以试一下,随便教下弱弱的我。

你可能感兴趣的:(数据结构)