最大生成树——LCA

今天说是要练习LCA结果找了道题看着题解打完了,如此惭愧,Lca还得好好理解啊,感觉在最大生成树上做有点异样,可能还是不是很理解吧,在noip前一定要再把这道题再a一遍,好题啊。

这是2013noipt3的题,难度适中,比以往的简单没让人想不出来思路虽然我第一遍看也没想起来但是题解易懂,是我这种低级选手能做的题,所以今天下午选择做这道题,看着题解打了3h终于大功告成,一部分是抄的真心不会啊lca,昨天刚学还是打不下了。打完代码后按了下F7,嗯,100+errors真的很难受,代码能力过差,然后调试调了30多分钟,各种i打成j各种w打成fa,真的是醉了,按照汤神的话来说就是打代码的时候你在想什么,汤神看代码很准的基本上没什么错误orztql,于是乎和上一遍lca并不一样的不在于求最大生成树(这个非常好打)而是定根节点,要不这个最大的生成树可以看成一条线,如果不定根节点的话,谁知道你的最近公共祖先是谁,然后就是倍数的问题二进制的拆分,直接从20开始不必log(n)/log(i);因为n不可能超过2的20次方,尽管这样浪费一点时间,但是无关紧要,还有就是一点不是很理解的就是lca的初始化不是很懂啊,尽管明白那是个状态转移,但是呢打起来的时候还是迷茫,不理解内层因为i是从20开始的,于是乎到达很大的i的时候那时的祖先都是已经达到的祖先了这些都其实没什么用,还是写篇博客更好,又加深了理解,很棒呢!

下面是代码了接近150行代码=-= 好累。

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<ctime>
#include<map>
#include<vector>
#include<stack>
#define inf 10000007
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int maxn=50002;
struct bwy 
{
    int x,y,dis;
}s[maxn];
int e[maxn],nex[maxn],lin[maxn],ver[maxn],len;
int f[maxn],fa[maxn][30],w[maxn][30],depth[maxn],vis[maxn];
void add(int x,int y,int z)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
    e[len]=z;
}
int n,m,k;
int my(bwy x,bwy y)
{
    return x.dis>y.dis;
}
int getfather(int x)
{
    if(x==f[x])
        return x;
    return f[x]=getfather(f[x]);
}
void kruskal()
{
    for(int i=1;i<=n;i++)
        f[i]=i;
    sort(s+1,s+1+m,my);
    for(int i=1;i<=m;i++)
    {
        int xx=getfather(s[i].x);
        int yy=getfather(s[i].y);
        if(xx!=yy)
        {
            f[xx]=yy;
            add(s[i].x,s[i].y,s[i].dis);
            add(s[i].y,s[i].x,s[i].dis);
        }
    }
}
void dfs(int num)
{
    vis[num]=1;
    for(int i=lin[num];i!=0;i=nex[i])
    {
        int tn=ver[i];
        if(vis[tn]==1)
            continue;
        depth[tn]=depth[num]+1;
        fa[tn][0]=num;
        w[tn][0]=e[i];
        dfs(tn);
    }
    return;
}
int lca(int x,int y)
{
    if(getfather(x)!=getfather(y))
        return -1;
    int ans=inf;
    if(depth[x]>depth[y])
        swap(x,y);
    for(int i=20;i>=0;i--)
    {
        if(depth[fa[y][i]]>=depth[x])
        {
            ans=min(ans,w[y][i]);
            y=fa[y][i];
        }
    }
    if(x==y)return ans;
    for(int i=20;i>=0;i--)
    {
        if(fa[x][i]!=fa[y][i])
        {
            ans=min(ans,min(w[x][i],w[y][i]));
            x=fa[x][i],y=fa[y][i];
        }
    }
    ans=min(ans,min(w[x][0],w[y][0]));
    return ans;
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {    
        s[i].x=read();s[i].y=read();s[i].dis=read();
    }
    kruskal();
    for(int i=1;i<=n;i++)
    {
        if(vis[i]!=1)
        {
            depth[i]=1;
            dfs(i);
            fa[i][0]=i;
            w[i][0]=inf;
        }
    }
    for(int i=1;i<=20;i++)
        for(int j=1;j<=n;j++)
        {
            fa[j][i]=fa[fa[j][i-1]][i-1];
            w[j][i]=min(w[j][i-1],w[fa[j][i-1]][i-1]);
        }
    k=read();
    for(int i=1;i<=k;i++)
    {
        int x,y;
        x=read();y=read();
        cout<<lca(x,y)<<endl;
    }
    return 0;
}
View Code

一天又过去,希望时间没白费。

萧瑟兰成看老去,为怕多情,不作怜花句。
原文地址:https://www.cnblogs.com/chdy/p/9693251.html