zoukankan      html  css  js  c++  java
  • codevs 1036 商务旅行 (倍增LCA)

    /*
    在我还不知道LCA之前 暴力跑的SPFA 
    70分 三个点TLE 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    struct node
    {
        int u;
        int t;
        int pre;
    };
    node a[30010*2+100];
    queue<int>q;
    int n,qq,x[30010],num,head[30010],f[30010],dis[30010],sum;
    void add(int from,int to)
    {
        num++;
        a[num].pre=head[from];
        a[num].u=to;
        a[num].t=1;
        head[from]=num;
    }
    void SPFA()
    {
        int i,j;
        for(j=1;j<=qq-1;j++)
          {
              memset(dis,127/3,sizeof(dis));
            memset(f,0,sizeof(f));
              int s=x[j];
              int v=x[j+1];
              q.push(s);
              f[s]=1;
              dis[s]=0;
              do
              {
                  int k=q.front();
                  q.pop();
                  f[k]=0;
                  for(i=head[k];i;i=a[i].pre)
                    {
                        if(dis[a[i].u]>dis[k]+a[i].t)
                          {
                              dis[a[i].u]=dis[k]+a[i].t;
                              if(f[a[i].u]==0)
                                {
                                    q.push(a[i].u);
                                    f[a[i].u]=1;
                          }
                      }
                  }
              }while(!q.empty());
            sum=sum+dis[v];
          } 
    }
    int main()
    {
        int i,o,u;
        cin>>n;
        for(i=1;i<=n-1;i++)
          {
              cin>>o>>u;
              add(o,u);
              add(u,o);
          }
        cin>>qq;
        for(i=1;i<=qq;i++)
          cin>>x[i];
        SPFA();
        cout<<sum;
    }
    /*
    倍增LCA 
    将旅行路线两两拆开 求相邻两点的距离 
    即求他们到lca的距离和 
    这里用倍增法实现求距离 fa[i][j]表示i节点往上2^j层的节点是什么
    因为1 2 4 8 16...做和可以表示所有的整数 所以保证覆盖整张图
    先Dfs建图 顺面几下每个节点的所在层 以及fa[i][0] 的值
    然后DP预处理fa数组
    然后就是求到lca的距离了
    这里我们求出只需要求出lca是谁 那么两点之间的最小距离就是
    deep[p1]+deep[p2]-2*deep[anc] deep是深度
    剩下的就仅仅是找lca是谁了
    对于一组a ,b  如果他们在同一层的话 我们只需要同时向上移动他俩 知道a==b
     
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 30010
    #define S 16
    int n,m,num,head[maxn],fa[maxn][S+5],deep[maxn],p1,p2,ans;
    struct node
    {
        int u,v,pre;
    }e[maxn*2];
    void Add(int from,int to)
    {
        num++;
        e[num].u=from;
        e[num].v=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    void swap(int &a,int &b)
    {
        int t=a;a=b;b=t;
    }
    void init()
    {
        scanf("%d",&n);
        int x,y;
        for(int i=1;i<=n-1;i++)
          {
              scanf("%d%d",&x,&y);
              Add(x,y);Add(y,x);
          }
    }
    void get_fa()
    {
        for(int j=1;j<=S;j++)
          for(int i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];//数学方法展开就是fa[i][j] 
    }
    void Dfs(int now,int from,int c)//得带每个点的所在层 
    {
        fa[now][0]=from;
        deep[now]=c;
        for(int i=head[now];i;i=e[i].pre)
          if(e[i].v!=from)
            Dfs(e[i].v,now,c+1);
    }
    int get_same(int a,int t)//计算a往上t层是啥 
    {
        for(int i=1;i<=t;i++)
          a=fa[a][0];
        return a;
    }
    int LCA(int a,int b)
    {
        if(deep[a]<deep[b])swap(a,b);//保证a深度大 
        a=get_same(a,deep[a]-deep[b]);//得到a向上deep[a]-deep[b]层是谁 即a的与b同层的祖先是谁 
        if(a==b)return a;//如果汇聚到一个点 就不用往上了 
        for(int i=S;i>=0;i--)//这里有套路 从最大值开始循环 一开始 fa[a][i]  fa[b][i]一定是相等的
                             //因为此时位于他们lca之上 然后往下 这里可以覆盖每一层 
          if(fa[a][i]!=fa[b][i])
            {
              a=fa[a][i];
              b=fa[b][i];
            }
        return fa[a][0];
    }
    int main()
    {
        init();
        Dfs(1,1,0);
        get_fa();
        scanf("%d%d",&m,&p1);
        for(int i=1;i<=m-1;i++)
          {
              scanf("%d",&p2);
              int anc=LCA(p1,p2);
              ans+=deep[p1]+deep[p2]-2*deep[anc];
              p1=p2;
          }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    bootstrap
    jQuery快速入门
    前端jQuery
    前端BOM和DOM
    前端js
    前端css
    前端知识之HTML内容
    线程池
    线程
    LightOJ
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/5542449.html
Copyright © 2011-2022 走看看