社区讨论

20pts求条

P10289[GESP样题 八级] 小杨的旅游参与者 2已保存回复 2

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
2 条
当前快照
1 份
快照标识符
@mhizk542
此快照首次捕获于
2025/11/03 18:17
4 个月前
此快照最后确认于
2025/11/03 18:17
4 个月前
查看原帖
lca+bfs,rt,悬关
CPP
#include<bits/stdc++.h>
using namespace std;
const int N = 200020;
vector<int>e[N];
bool vis[N];
bool t[N];
int fa[N][20];
int dep[N];
int dis[N];
typedef pair<int,int> pii;
#define fi first
#define se second
#define ll long long
int n;
void dfs(int u,int f){
	for(auto v:e[u]){
		if(v==f)continue;
		fa[v][0] = u;
		dep[v] = dep[u]+1;
		dfs(v,u);
	}
}
void init(){
	for(int j = 1;j<=19;j++){
		for(int i = 1;i+(1<<j)-1<=n;i++){
			fa[i][j] = fa[fa[i][j-1]][j-1];
		}
	}
}
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i = 19;i>=0;i--){
		if(dep[fa[x][i]]>=dep[y])x = fa[x][i];
	}
	if(x==y)return x;
	for(int i = 19;i>=0;i--){
		if(fa[x][i]!=fa[y][i])x = fa[x][i],y = fa[y][i];
	}
	return fa[x][0];
}
void bfs(){
	queue<int>q;
	for(int i = 1;i<=n;i++)if(t[i])q.push(i);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		if(vis[u])continue;
		vis[u] = 1;
		for(auto v:e[u]){
			if(vis[v])continue;
			dis[v] = dis[u]+1;
			q.push(v);
		}
	}
}
int main(){
	int k,q;
	cin>>n>>k>>q;
	//step1:倍增求LCA
	//step2:求最近传送门距离
	//step3:分讨,取min
	//一开始没想出来的原因:没看到是树。。。
	//下次要认真读题~ 
	//tips:任意一点为根遍历均可
	//18:34开始写代码 
	//update:一开始疏漏的地方:把所有有传送门的压入队列,bfs打标记,保证不会重复遍历
	//k==0要特判 
	for(int i = 1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	for(int i = 1;i<=k;i++){
		int u;
		cin>>u;
		t[u] = 1;
	}
	dep[1] = 1;
	dfs(1,-1); 
	init();
	bfs();
	while(q--){
		int u,v;
		cin>>u>>v;
		int s1 = dep[u]+dep[v]-2*dep[lca(u,v)];
		int s2 = dis[u]+dis[v];
		if(k==0)s2 = 1e9+10;
		cout<<min(s1,s2)<<"\n"; 
	}
	return 0;
} 
HasNoNamekeshuhan ToastBread XaoWa118 急!

回复

2 条回复,欢迎继续交流。

正在加载回复...