1036 商务旅行

来源:互联网 发布:asp信息录入系统源码 编辑:程序博客网 时间:2024/05/22 09:04

直接放代码了,练习倍增

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;int n,m,q,cnt,tot,deep[30001],head[30001],fa[30001][17];bool vis[30001];struct e{    int next,to;}e[200001];void add(int u,int v){    e[++cnt].to=v;    e[cnt].next=head[u];    head[u]=cnt;}void dfs(int x){    vis[x]=1;    for(int i=1;i<=16;i++)    {        if(deep[x]<(1<<i))        break;        fa[x][i]=fa[fa[x][i-1]][i-1];//lca的递推公式     }    for(int i=head[x];i;i=e[i].next)//图的遍历     {        if(vis[e[i].to])        continue;        fa[e[i].to][0]=x;        deep[e[i].to]=deep[x]+1;        dfs(e[i].to);    }}int lca(int x,int y){    if(deep[x]<deep[y])    swap(x,y);    int t=deep[x]-deep[y];    for(int i=0;i<=16;i++)        if((1<<i)&t)//找不会超过两个数的最近公共祖先的能跳的最大值         x=fa[x][i];//跳到那个地方     for(int i=16;i>=0;i--)    {        if(fa[x][i]!=fa[y][i]) //还没有找到lca         {            x=fa[x][i];            y=fa[y][i];        }    }    if(x==y)    return x;    return fa[x][0];//返回最后找到的lca }int main(){    scanf("%d",&n);    for (int i=1;i<n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        add(x,y);        add(y,x);        fa[y][0]=x;        fa[x][0]=y;//互为对方的父节点     }    for(int i = 1; i <= n; i ++)    {        if(!vis[i])//图的遍历         dfs(i);    }    int m,now,last,ans=0;    scanf("%d%d",&m,&last);//询问的点和第一个点     for (int i=2;i<=m;i++)    {        scanf("%d",&now);        ans+=deep[last]+deep[now]-deep[lca(last,now)]*2;//(deep[last]-deep[lca(last,now)]+(deep[now]-deep[lca(last,now)]))         last=now;//更新     }    printf("%d\n",ans);//结果     return 0;}
2 0
原创粉丝点击