p2912 牧场散步 (USACO08OCT)

z

你没有发现两个字里的blog都不一样嘛 qwq

题目描述-->p2912 牧场散步

题意概括

给定一个,给你Q个询问,每次询问输入一个二元组\((x,y)\),要求求出\((x,y)\)的距离.

明显带权lca.

这里写一下递推式
\[ f[u][i]=f[f[u][i-1]][i-1] \]

\[ gw[u][i]=gw[f[u][i-1]][i-1]+gw[u][i-1] \]

定义:

\(f[u][i]\)代表\(u\)向上跳\(2^i\)步到达的节点.

\(gw[u][i]\)代表\(u\)向上跳\(2^i\)步到达的节点的边权和.

为什么\(f[u][i]=f[f[u][i-1]][i-1]\)

我们从\(u\)到达\(f[u][i]\)需要\(2^i\)步,而到达\(f[u][i-1]\)需要\(2^{i-1}\)步,再从这个位置跳\(2^{i-1}\)步,的话就到达了\(f[u][i]\)
\[ 2^{i-1}+2^{i-1}=2*2^{i-1}=2^{i} \]
又因为我们处理\(f[u][i-1]\)一定比处理\(f[u][i]\)要早,所以这样转移即可.

初始化

f[u][0]=fa;
gw[u][0]=edge[i].w;//即连向u的边权.

然后这样这个题就变成了裸的带权lca问题 qwq.

---------------------代码---------------------

#include<bits/stdc++.h>
#define R register
#define N 1008
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,head[N],tot,m;
int depth[N],f[N][18],gw[N][18];
struct cod{int u,v,w;}edge[N<<1+8];
inline void add(int x,int y,int z)
{
    edge[++tot].u=head[x];
    edge[tot].v=y;
    edge[tot].w=z;
    head[x]=tot;
}
void dfs(int u,int fa,int dis)
{
    depth[u]=depth[fa]+1;
    f[u][0]=fa;gw[u][0]=dis;
    for(R int i=1;(1<<i)<=depth[u];i++)
        f[u][i]=f[f[u][i-1]][i-1],
        gw[u][i]=gw[f[u][i-1]][i-1]+gw[u][i-1];
    for(R int i=head[u];i;i=edge[i].u)
    {
        if(edge[i].v==fa)continue;
        dfs(edge[i].v,u,edge[i].w);
    }
}
inline int lca(int x,int y)
{
    if(depth[x]>depth[y])swap(x,y);
    int ans=0;
    for(R int i=17;i>=0;i--)
        if(depth[y]-(1<<i)>=depth[x])
            ans+=gw[y][i],y=f[y][i];
    if(x==y)return ans;
    for(R int i=17;i>=0;i--)
    {
        if(f[x][i]==f[y][i])continue;
        ans+=gw[x][i]+gw[y][i];
        y=f[y][i],x=f[x][i];
    }
    return (ans+gw[x][0]+gw[y][0]);
}
int main()
{
    in(n),in(m);
    for(R int i=1,x,y,z;i<n;i++)
    {
        in(x),in(y),in(z);
        add(x,y,z);add(y,x,z);
    }
    dfs(1,0,0);
    for(R int x,y;m;m--)
    {
        in(x),in(y);
        printf("%d\n",lca(x,y));
    }
}

猜你喜欢

转载自www.cnblogs.com/-guz/p/9709000.html