首页 > 其他分享 >P8855 [POI2002]商务旅行

P8855 [POI2002]商务旅行

时间:2022-11-18 17:24:58浏览次数:41  
标签:son fx dfs2 int top P8855 dep POI2002 商务旅行

简要题意

给出一个 \(N\) 个节点的树和一个长度为 \(M\) 的序列 \(S\)。你需要从 \(1\) 出发,依次经过 \(S\) 中的所有点,求至少需要经过的边数。

\(1 \le N \le 30000\)

思路

首先先给出一个结论:树上两点之间的最短离,等于两点的深度和减去其最近公共祖先的两倍。

证明如下(令 \(d(u)\) 为 \(u\) 的深度,\(r\) 为树根,\(a(u,v)\) 为从 \(u\) 到 \(v\) 的最短距离,\(l(u,v)\) 为 \(u,v\) 的最近公共祖先):

\[\begin{aligned} &d(u)+d(v)-2d(l(u,v))\\ &=a(r,u)+a(r,v)-a(r,l(u,v))-a(r,l(u,v))\\ &=a(l(u,v),u)+a(r,l(u,v))+a(l(u,v),v)+a(r,l(u,v))-a(r,l(u,v))-a(r,l(u,v))\\ &=a(l(u,v),u)+a(l(u,v),v)\\ &=a(u,v) \end{aligned} \]

然后的过程就很简单了,使用树剖(用于求最近公共祖先)和上述结论求出 \(a(1,S_1)+a(S_1,S_2)+\cdots+a(S_{M-1}+S_{M})\) 即可。

时间复杂度 \(O(N+M\log N)\),可以通过本题。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 500005;

struct edge {
	int nxt, to;
} g[N << 1];
int head[N << 1], ec;
void add(int u, int v) {
	g[++ec].nxt = head[u];
	g[ec].to = v;
	head[u] = ec;
}

int root;
int siz[N], son[N], fa[N], top[N], dep[N];
void dfs1(int u, int father, int deep) {
	dep[u] = deep;
	siz[u] = 1;
	fa[u] = father;
	for (int i = head[u]; i; i = g[i].nxt) {
		int v = g[i].to;
		if (v == father) {
			continue;
		}
		dfs1(v, u, deep + 1);
		siz[u] += siz[u];
		if (siz[v] >= siz[son[u]]) {
			son[u] = v;
		}
	}
}

void dfs2(int u, int father, int t) {
	top[u] = t;
	if (son[u])dfs2(son[u], u, t);
	for (int i = head[u]; i; i = g[i].nxt) {
		int v = g[i].to;
		if (v == father) {
			continue;
		}
		if (v == son[u]) {
			continue;
		}
		dfs2(v, u, v);
	}
}

int lca(int x, int y) {
	int fx = top[x], fy = top[y];
	while (fx != fy) {
		if (dep[fx] < dep[fy]){
			swap(fx, fy);
			swap(x, y);
		}
		x = fa[fx], fx = top[x];
	}
	if (dep[x] > dep[y]) {
		return y;
	}
	else return x;
}


int n,m,s;

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	dfs1(1,0,1);
	dfs2(1,0,1);
	cin>>m;
	int ret=0,u=1,v=0;
	while(m--){
		cin>>v;
		ret+=(dep[u]+dep[v]-2*dep[lca(u,v)]); // 运用结论
		u=v;
	}
	cout<<ret;
	return 0;
}

标签:son,fx,dfs2,int,top,P8855,dep,POI2002,商务旅行
From: https://www.cnblogs.com/zheyuanxie/p/p8855.html

相关文章