zoukankan      html  css  js  c++  java
  • 【BZOJ】1602:[Usaco2008 Oct]牧场行走

    【算法】最近公共祖先(LCA)

    【题解】

    点x,y到最近公共祖先z的距离之和相当于x,y到根的距离减去两倍z到根的距离,

    即ans=dis[x]+dis[y]-2*dis[z]

    记得边数组要开两倍!!!T_T

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const double eps=1e-3;
    const int maxn=1010;
    struct cyc{int from,to,w;}e[maxn*2];
    int dis[maxn],deep[maxn],f[maxn][15],n,q,cnt,head[maxn];
    bool vis[maxn];
    void insert(int u,int v,int w)
    {cnt++;e[cnt].from=head[u];e[cnt].to=v;e[cnt].w=w;head[u]=cnt;}
    void dfs(int x)
    {
        vis[x]=1;
        for(int i=1;(1<<i)<=deep[x];i++)
         f[x][i]=f[f[x][i-1]][i-1];
        for(int i=head[x];i;i=e[i].from)
         if(!vis[e[i].to])
          {
              int now=e[i].to;
              deep[now]=deep[x]+1;
              dis[now]=dis[x]+e[i].w;
              f[now][0]=x;
              dfs(now);
          }
    }
    int lca(int x,int y)
    {
        if(deep[x]<deep[y])swap(x,y);
        int d=deep[x]-deep[y];
        for(int i=0;(1<<i)<=d;i++)
         if((1<<i)&d)x=f[x][i];
        if(x==y)return x;
        for(int i=10;i>=0;i--)
         if(f[x][i]!=f[y][i])
          x=f[x][i],y=f[y][i]; 
        return f[x][0];
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<n;i++)
         {
             int u,v,w;
             scanf("%d%d%d",&u,&v,&w);
             insert(u,v,w);
             insert(v,u,w);
         }
        dfs(1);
        for(int i=1;i<=q;i++)
         {
             int p1,p2;
             scanf("%d%d",&p1,&p2);
             printf("%d
    ",dis[p1]+dis[p2]-2*dis[lca(p1,p2)]);
         }
        return 0;
    }
    View Code

    也可以记录g[x][i],则不必减去多余的。

    事实证明在一些简单的树上路径问题上,倍增比链剖更有优势。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=1010;
    struct edge{int v,from,w;}e[maxn*3];
    int n,first[maxn],deep[maxn],f[maxn][20],g[maxn][20],v[maxn],tot,lca,q;
    void insert(int u,int v,int w)
    {tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
    void dfs(int x,int fa)
    {
        for(int i=1;(1<<i)<=deep[x];i++)
        {
            f[x][i]=f[f[x][i-1]][i-1];
            g[x][i]=g[x][i-1]+g[f[x][i-1]][i-1];
        }
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa)
        {
            int y=e[i].v;
            f[y][0]=x;
            deep[y]=deep[x]+1;
            g[y][0]=e[i].w;
            dfs(y,x);
        }
    }
    int find(int x,int y)
    {
        int ans=0;
        if(deep[x]<deep[y])swap(x,y);
        int d=deep[x]-deep[y]; 
        for(int i=0;(1<<i)<=deep[x];i++)
            if((1<<i)&d){ans+=g[x][i];x=f[x][i];}
        if(x==y)return ans;
        for(int i=20;i>=0;i--)
        if((1<<i)<=deep[x]&&f[x][i]!=f[y][i])
        {
            ans+=g[x][i]+g[y][i];
            x=f[x][i];y=f[y][i];
        }
        lca=f[x][0];
        return ans+g[x][0]+g[y][0];
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<n;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            insert(u,v,w);
            insert(v,u,w);
        }
        dfs(1,-1);
        for(int i=1;i<=q;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            printf("%d
    ",find(u,v));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    windy数
    微信授权网页登陆,oauth
    Win7/Win2008下IIS配置Asp网站启用父路径的设置方法(已解决)
    Html5学习笔记1 元素 标签 属性
    com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown database &#39;user&#39;
    POJ 3978(求素数)
    java内存模型(Java Memory Model)
    【Unity3D自学记录】Unity3D之自制小钟表
    HDU4126Genghis Khan the Conqueror(最小生成树+并查集)
    gcc学习(一)[第二版]
  • 原文地址:https://www.cnblogs.com/onioncyc/p/5763625.html
Copyright © 2011-2022 走看看