CF-div3-629-E - ツリークエリ

アイデア解析

質問の意味:このチェーンの点からチェーン内のすべてのポイント、または距離が1であるように、私たちはチェーンの木を見つけてみましょう;
分析:
1.チェーン1には、この時点での距離場合は、ポイントを説明チェーンの父。
2.最初に考えたのは深い終わり深く、より多くのこのチェーンがポイントの事をカバーすることができるので、確かにこのチェーンの深さの最深点までのルートから、このチェーンを見つける方法を考えること。
3.次に限り父親または他のノードは、この点に判断されるように、それの一方の鎖上に存在しません。判定は、現在のノードまたは父親でない限り、LCAの決意(現在のノード、最も深いノード)=現在のノードとして、連鎖していません。

方法:スプリットツリーチェーン得LCA、父、深く、そして最深点を見つけ、他の点は、それがLCAへの状態か否かを判断します。

コード

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

const int maxn = 2e5+100;
vector<int> g[maxn];
int fa[maxn],depth[maxn],sz[maxn],son[maxn],id[maxn],rk[maxn],top[maxn],bot[maxn];
int cnt = 0;
int root;

void dfs(int x,int deep){
	depth[x] = deep;
	sz[x] = 1;
	for(int li = 0;li<g[x].size();li++){
		int i = g[x][li];
		if(i == fa[x]) continue;
		fa[i] = x;
		dfs(i,deep+1);
		sz[x] += sz[i];
		if(sz[i] > sz[son[x]]) son[x] = i;
	}
}

void dfs2(int x,int tp){
	top[x] = tp;
	id[x] = ++cnt;
	rk[cnt] = x;
	if(son[x]) dfs2(son[x],tp),bot[x] = bot[son[x]];
	else bot[x] = x;
	for(int li=0;li<g[x].size();li++){
		int i = g[x][li];
		if(i != fa[x] && i != son[x])
			dfs2(i,i);
	}
}

int lca(int u,int v){
	while(top[u] != top[v]){
		if(depth[top[u]] < depth[top[v]]) swap(u,v);
		u = fa[top[u]];
	}
	if(depth[u] < depth[v]) return u;
	return v;
}

int node[maxn];
void solve(){
	int k;
	cin>>k;
	int maxDeep = 0,maxNode;
	for(int i=1;i<=k;i++) {
		cin>>node[i];
		if(maxDeep <= depth[node[i]]){
			maxDeep = depth[node[i]];
			maxNode = node[i];
		}
	}
	for(int i=1;i<=k;i++){
		if(node[i] == maxNode) continue;
		int LCA = lca(maxNode,node[i]);
		if(!(LCA == node[i] || LCA == fa[node[i]])){
			puts("NO");
			return;
		}
	}
	puts("YES");
}

int main(){
	ios::sync_with_stdio(false);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n-1;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	root = 1;
	dfs(root,1);
	dfs2(root,root);
	while(m--){
		solve();
	}
	return 0;
}

おすすめ

転載: www.cnblogs.com/fisherss/p/12580644.html