2017-10-24LCA

今天复习LCA专题,做了几道题

其一是codevs的2370-小机房的树极其裸的一道题

是不是很裸?直接上代码了。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 50010 
int head[maxn],deep[maxn],dis[maxn];
int ecnt,n,f[maxn][35];

struct edge
{
    int u,v,w;
    int next;
}E[maxn<<1];

void addedge(int u,int v,int w)
{
    E[++ecnt].u = u;
    E[ecnt].v = v;
    E[ecnt].w = w;
    E[ecnt].next = head[u];
    head[u] = ecnt;
}

void dfs(int x,int fx)
{
    deep[x] = deep[fx]+1;
    f[x][0] = fx;
    for(int i = head[x]; i ; i = E[i].next){
        int v = E[i].v;
        if(v == fx) continue;
        dis[v] = dis[x] + E[i].w;
        dfs(v,x);
    }
}

void init()
{
    for(int j = 1; (1<<j) <= n; j ++)
        for(int i = 1; i <= n; i ++)
            if(deep[i] >= (1<<j))
                f[i][j] = f[f[i][j-1]][j-1];
}

int getfather(int a,int b)
{
    if(deep[a] < deep[b]) swap(a,b);
    int d = deep[a] - deep[b];
    for(int j = 30; j >= 0; j --)
        if(d&1<<j)
        {
            a = f[a][j];
        }
    if(a == b) return a;
    for(int j = 30; j >= 0 ; j --)
        if(f[a][j]!= f[b][j])
        {
            a = f[a][j];
            b = f[b][j];
        }
    return f[a][0];
}

int main()
{
    scanf("%d",&n);int u,v,w,q;
    for(int i = 1; i < n; i ++)
    {
        scanf("%d%d%d",&u,&v,&w);
        u++;v++;
        addedge(u,v,w);
        addedge(v,u,w);
    }
    dfs(1,0);
    init();
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d",&u,&v);
        u++;v++;
        int fx = getfather(u,v);
        printf("%d\n",dis[u]+dis[v] - 2*dis[fx]);            
    }
}

第二题也是codevs1036-商务旅行

这道题乍一看以为是最短路,但是它是树上的,所以我们可以直接求每两个点的LCA然后加起来就可以了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 30010
using namespace std;
int ecnt,head[maxn],deep[maxn],fa[maxn],top[maxn],size[maxn],son[maxn];
struct edge
{
    int u,v,next;
}E[maxn<<1];

void addedge(int u,int v)
{
    E[++ecnt].u=u;
    E[ecnt].v=v;
    E[ecnt].next=head[u];
    head[u]=ecnt;
}

void dfs(int x)
{
    size[x]=1;
    for(int i=head[x];i;i=E[i].next)
    {
        int v=E[i].v;
        if(fa[x]==v)continue;
        fa[v]=x;
        deep[v]=deep[x]+1;
        dfs(v);
        size[x]+=size[v];
        if(size[son[x]]<size[v])son[x]=v;    
    }
}

void dfs2(int x,int tp)
{
    top[x]=tp;
    if(son[x])dfs2(son[x],tp);
    for(int i=head[x];i;i=E[i].next)
    {
        int v=E[i].v;
        if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
}

int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return deep[x]>deep[y]?y:x;
}

int main()
{
    int n,tmp,m,u,v,ans=0,a;
    scanf("%d",&n);
    for(int i=1;i<n;++i)
    {
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);    
    }
    dfs(1);dfs2(1,1);
    scanf("%d%d",&m,&tmp);
    for(int i=2;i<=m;++i)
    {
        scanf("%d",&a);
        ans+=deep[tmp]+deep[a]-deep[lca(a,tmp)]*2;
        tmp=a;
    }
    printf("%d",ans);
    return 0;
} 

第三道题是bzoj的1787

这道题是求三个点的最近公共祖先,我们可以先求出每两个点的LCA k1,k2,k3然后比较,假设k1==k2那么肯定选k3为集结点,如果k1为集结点,那么肯定要有两个人从k3走过来,不满足最少的题意。有思路就很舒服了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 500005
using namespace std;
int ecnt,head[maxn],siz[maxn],son[maxn],deep[maxn],fa[maxn],top[maxn],n,m;
struct edge{
    int v,next;
}E[maxn<<1];
void add(int u,int v)
{
    E[++ecnt].v=v;
    E[ecnt].next=head[u];
    head[u]=ecnt;
}
void dfs(int x)
{
    siz[x]=1;
    for(int i=head[x] ; i ; i=E[i].next )
    {
        int v=E[i].v;
        if(fa[x]==v)continue;
        deep[v]=deep[x]+1;fa[v]=x;
        dfs(v);
        siz[x]+=siz[v];
        if(siz[son[x]]<siz[v])son[x]=v; 
    }
}
void dfs2(int x,int tp)
{
    top[x]=tp;
    if(son[x])dfs2(son[x],tp);
    for(int i=head[x] ; i ; i=E[i].next )
    {
        int v=E[i].v;
        if(son[x]==v||fa[x]==v)continue;
        dfs2(v,v);    
    } 
}
int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return deep[x]<deep[y]?x:y;
}
inline int read()
{
    int ret(0);
    char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        ret=(ret<<1)+(ret<<3)+ch-'0';
        ch=getchar();
    }
    return ret;
}
int main()
{
    int u,v,a,b,c,t1,t2,t3,jud,tmp,fu;
    n=read();m=read();
    for(int i=1 ; i<n ; ++i )
    {
        u=read();v=read();
        add(u,v);add(v,u);
    }
    dfs(1);dfs2(1,1);
    while(m--)
    {
        a=read();b=read();c=read();
        t1=lca(a,b);t2=lca(a,c);t3=lca(b,c);
        if(t1==t2)
        {
            fu=t3;
            jud=lca(t3,a);
            tmp=deep[b]+deep[c]+deep[a]-deep[t3]-deep[jud]*2;
        }
        if(t2==t3)
        {
            fu=t1;
            jud=lca(t1,c);
            tmp=deep[b]+deep[c]+deep[a]-deep[t1]-deep[jud]*2;
        }
        if(t1==t3)
        {
            fu=t2;
            jud=lca(t2,b);
            tmp=deep[b]+deep[c]+deep[a]-deep[t2]-deep[jud]*2;
        }
        printf("%d %d\n",fu,tmp);
    }
    return 0;
}

 

posted @ 2017-10-24 21:00  luoxk  阅读(102)  评论(0编辑  收藏  举报