LOJ #10134. 「一本通 4.4 练习 1」Dis

做这道题需要知道一个性质:树上 \(x,y\) 两点的距离为 \(dis(x)+dis(y)-2dis(LCA(x,y))\),其中 \(dis(i)\) 表示 \(i\) 点离根节点的距离,\(LCA(i,j)\) 表示 \(i,j\) 两点的 LCA(最近公共祖先)。

然后就直接水过去了。在预处理 fa 数组时直接将 dis 数组带着预处理一遍就 A 掉了(这什么垃圾题解)。

Code:

#include <bits/stdc++.h>
using namespace std;
const int maxN=10005,logn=15;
struct Edge {int to,val,nxt;}edge[maxN<<1];
int n,m,tot,fa[maxN][logn],dep[maxN],hd[maxN],dis[maxN];
void add(int,int,int),dfs(int,int);
int LCA(int,int),query(int,int);
int main() {
	scanf("%d%d",&n,&m);
	for (int i=1;i<n;i++) {
		int x,y,v;scanf("%d%d%d",&x,&y,&v);
		add(x,y,v);
		add(y,x,v);
	}
	dfs(1,1);
	for (;m;m--) {
		int x,y;scanf("%d%d",&x,&y);
		printf("%d\n",query(x,y));
	}
	return 0;
}
void add(int x,int y,int v) {
	edge[++tot].to=y;
	edge[tot].val=v;
	edge[tot].nxt=hd[x];
	hd[x]=tot;
}
void dfs(int u,int d) {
	dep[u]=d;
	for (int i=hd[u];i;i=edge[i].nxt) {
		int o=edge[i].to;
		if (dep[o]) continue;
		fa[o][0]=u;
		for (int j=1;fa[o][j-1];j++)
			fa[o][j]=fa[fa[o][j-1]][j-1];
		dis[o]=dis[u]+edge[i].val;
		dfs(o,d+1);
	}
}
int LCA(int u,int v) {
	if (dep[u]<dep[v]) swap(u,v);
	for (int i=logn;~i;i--)
		if (dep[u]-(1<<i)>=dep[v]) u=fa[u][i];
	if (u==v) return u;
	for (int i=logn-1;~i;i--)
		if (fa[u][i]!=fa[v][i]) {
			u=fa[u][i];
			v=fa[v][i];
		}
	return fa[u][0];	
}
int query(int u,int v) {return dis[u]+dis[v]-(dis[LCA(u,v)]<<1);}
posted @ 2020-04-04 21:28  Aehnuwx  阅读(248)  评论(0编辑  收藏  举报