洛谷原题链接:P2912 [USACO08OCT] Pasture Walking G
题意简化:给定一棵树,求Q个询问链(x,y)的长度
容易想到LCA,然后考虑求长度,可以通过倍增法求(x,LCA(x,y)),(y,LCA(x,y)),然后求和即可
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2000;
int h[N],nx[N],to[N],vl[N];
int deep[N],anst[N][12],st[N][12];
int n,k,idx=1;
void build(int u,int v,int w)
{
to[idx]=v;
nx[idx]=h[u];
vl[idx]=w;
h[u]=idx++;
}
void dfs(int u,int fa)
{
deep[u]=deep[fa]+1;
anst[u][0]=fa;
for(int i=h[u];i;i=nx[i])
{
int v=to[i],w=vl[i];
if(v==fa) continue;
st[v][0]=w;
dfs(v,u);
}
}
void init()//预处理i的2^n祖先,(i,anst[i][n])的长度
{
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i<=n;i++)
{
anst[i][j]=anst[anst[i][j-1]][j-1];
// cout<<i<<" "<<j<<" "<<anst[i][j]<<endl;
if(anst[i][j-1])
st[i][j]=st[anst[i][j-1]][j-1]+st[i][j-1];
}
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
int d=deep[x]-deep[y];
for(int j=0;(1<<j)<=d;j++)
{
if(d & (1<<j))
x=anst[x][j];
}
if(x==y) return x;
for(int j=11;j>=0;j--)
{
if(anst[x][j]!=anst[y][j])
{
x=anst[x][j];
y=anst[y][j];
// cout<<x<<" "<<y<<endl;
}
if(anst[x][0]==anst[y][0]) break;
}
return anst[x][0];
}
int quary(int fa,int u)//倍增法求解(fa,u)长度
{
int d=deep[u]-deep[fa];
int res=0;
for(int j=0;(1<<j)<=d;j++)
{
if(d & (1<<j))
{
res+=st[u][j];
u=anst[u][j];
}
}
return res;
}
int main(){
cin>>n>>k;
for(int i=1;i<n;i++)
{
int x,y,w;
cin>>x>>y>>w;
build(x,y,w);
build(y,x,w);
}
dfs(1,0);
init();
for(int i=1;i<=k;i++)
{
int x,y;
cin>>x>>y;
int f=lca(x,y);
cout<<quary(f,x)+quary(f,y)<<"\n";
}
}
浙公网安备 33010602011771号