最近在写一些树上的东西,先发一波LCA的吧!

Posted cc123321

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最近在写一些树上的东西,先发一波LCA的吧!相关的知识,希望对你有一定的参考价值。

不会树剖的我只有去学tarjan和倍增了,个人觉得倍增比tarjan好打一点。。。

tarjan学习的地方

http://www.cnblogs.com/JVxie/p/4854719.html

个人写的模板(洛谷的模板题,左右移符号打翻了,挑了好久QAQ)

#include<cstdio>
#include<algorithm>
#define ll long long
#define maxn 500500 << 1
using namespace std;

ll head[maxn],head_quest[maxn],tot,n,m,u,v,val,root,f[maxn],ceng[maxn],zou[maxn];

struct st{
    ll v,next;
}s[maxn];

struct que{
    ll u,v,lca,next;
    que *es;
}quest[maxn];

void add(ll u,ll v)
{
    tot++;
    s[tot].v = v;
    s[tot].next = head[u];
    head[u] = tot;
}

void addquest(ll u,ll v)
{
    tot++;
    if(tot & 1) quest[tot].es = &quest[tot + 1];
    else quest[tot].es = &quest[tot - 1];
    quest[tot].u = u;
    quest[tot].v = v;
    quest[tot].next = head_quest[u];
    head_quest[u] = tot;
}

ll find(ll x)
{
    if(f[x] == x) return x;
    f[x] = find(f[x]);
    return f[x];
}

void dfs(ll fa,ll pos)
{
    ceng[pos] = ceng[fa] + 1;
    for(ll i=head[pos];i;i=s[i].next)
        if(s[i].v != fa)
            dfs(pos,s[i].v);
}

void tarjan(ll fa,ll pos)
{
    for(ll i=head[pos];i;i=s[i].next)
    {
        if(s[i].v == fa) continue;
        tarjan(pos,s[i].v);
    }
    for(ll i=head_quest[pos];i;i=quest[i].next)
    {
        if(zou[quest[i].v])
        {
            quest[i].lca = find(quest[i].v);
            quest[i].es -> lca = quest[i].lca;
        }
    }
    zou[pos] = 1;
    f[pos] = fa;
}

int main(){
    scanf("%lld%lld%lld",&n,&m,&root);
    for(ll i=1;i<n;i++)
    {
        scanf("%lld%lld",&u,&v);
        add(u,v);
        add(v,u);
    }
    
    dfs(0,root);
    
    tot = 0;
    for(ll i=1;i<=m;i++)
    {
        scanf("%lld%lld",&u,&v);
        addquest(u,v);
        addquest(v,u);
    }
    
    for(ll i=1;i<=n;i++) f[i] = i;
    tarjan(0,root);
    for(ll i=1;i<=2*m;i+=2)
        printf("%lld\\n",quest[i].lca);
}

 

接下来是倍增

学习:

http://www.cnblogs.com/FuTaimeng/p/5655616.html

 自己写的模板(在洛谷交的时候忘了边要开两倍QAQ)

#include<cstdio>
#include<algorithm>
#include<cmath>
#define maxn 1000500
#define ll long long 
using namespace std;
struct st{
    ll u,v,next;
}s[maxn];
ll n,m,u,v,root,tot,head[maxn],ceng[maxn],fa[maxn][20];

inline void add(ll u,ll v)
{
    tot++;
    s[tot].u = u;
    s[tot].v = v;
    s[tot].next = head[u];
    head[u] = tot;
}

inline void dfs(ll f,ll now)
{
    fa[now][0] = f;
    ceng[now] = ceng[f] + 1;
    for(ll i = head[now];i;i = s[i].next)
    {
        if(s[i].v != f)
            dfs(now,s[i].v);
    }
}

inline void init()
{
    for(ll j=1;(1<<j)<=n;j++)
        for(ll i=1;i<=n;i++)
            fa[i][j] = fa[fa[i][j-1]][j-1];  
}
 
inline ll lca(ll a,ll b)
{
    if(ceng[a] > ceng[b]) swap(a,b);
    ll cha = ceng[b] - ceng[a];
    for(ll i = 0;(1 << i) <= cha;i++)
    {
        if((1 << i) & cha) b = fa[b][i];
    }
    if(a != b)
    {
        for(ll i=(ll)log2(n);i>=0;i--)
        {
            if(fa[a][i] != fa[b][i])
            {
                a=fa[a][i];
                b=fa[b][i];
            }
        }
        a = fa[a][0];
    }
    return a;
}
int main(){
    scanf("%lld%lld%lld",&n,&m,&root);
    for(ll i=1;i<n;i++)
    {
        scanf("%lld%lld",&u,&v);
        add(u,v);
        add(v,u);
    }
    
    dfs(0,root);
    init();
    for(ll i=1;i<=m;i++)
    {
        scanf("%lld%lld",&u,&v);
        printf("%lld\\n",lca(u,v));
    }
} 

 

以上是关于最近在写一些树上的东西,先发一波LCA的吧!的主要内容,如果未能解决你的问题,请参考以下文章

LCA

最近公共祖先(lca)与树上叉分

树上最近公共祖先(LCA)的算法

LCA 与树上差分

[LCA]二月的最后一天来搞事情吧

树上倍增求LCA