P3233 [HNOI2014]世界树

题目描述

世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。

世界树的形态可以用一个数学模型来描述:世界树中有 n 个种族,种族的编号分别从 1 到 n,分别生活在编号为 1 到 n 的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为 1。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居地之间的距离为连接他们的道路的长度;例如,若聚居地 a 和 b 之间有道路,b 和 c 之间有道路,因为每条道路长度为 1 而且又不可能出现环,所以 a 与 c 之间的距离为 2。

出于对公平的考虑,第 i 年,世界树的国王需要授权 mi 个种族的聚居地为临时议事处。对于某个种族 x(x 为种族的编号),如果距离该种族最近的临时议事处为 y(y 为议事处所在聚居地的编号),则种族 x 将接受 y 议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则 y 为其中编号最小的临时议事处)。

现在国王想知道,在 q 年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。

输入格式

第一行为一个正整数 n,表示世界树中种族的个数。接下来 n−1 行,每行两个正整数 x,y,表示 x 聚居地与 y 聚居地之间有一条长度为 1 的双向道路。接下来一行为一个正整数 q,表示国王询问的年数。接下来 q 块,每块两行:第 i 块的第一行为 1 个正整数 mi,表示第 i 年授权的临时议事处的个数。第 i 块的第二行为 mi 个正整数 (h_1 , h_2 , h_3 , dots),表示被授权为临时议事处的聚居地编号(保证互不相同)。

输出格式

输出包含 q 行,第 i 行为 mi 个整数,该行的第 j (j=1,2,…,mi) 个数表示第 i 年被授权的聚居地 hj 的临时议事处管理的种族个数。

输入输出样例

输入 #1

10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8

输出 #1

1 9   
3 1 4 1 1   
10  
1 1 3 5   
4 1 3 1 1

说明/提示

对于 100% 的数据,N≤300000.

首先是虚树

一般的虚树题都是建完虚树就zz了 , 但这道题,dp也很曹丹啊

题中让求每个点覆盖几个点。我本人的第一想法就是bfs , 但肯定过不去

于是就看了题解 , 题解上有位大佬用了一波骚气的dfs爆切了这道题

首先dfs0 , 把一些基本的信息, 如(siz , d , f[][20] , dfn) 求出来。

建出虚树。

对每个询问 , 找到虚树上每个点最近的关键点

这个可以用两遍dfs 求出, 一次求字数内的,另一次求子树外的。

用pair存起来 , 记这个数组为g

在进行dfs3 , 这个是先进行第一步粗略的计算 , 先将这个节点的儿子中没用关键的siz全都加上

并且还得处理处 ,up[x] 表示x 到的它虚树上的父亲的儿子(最近的儿子) (说的不清楚。。看代码吧 ) 顺带记录一下每个点离他最近的关键点是谁,is[x]

dfs4 , 这个是最终的运算 , 考虑 x 与 x 的儿子v

如果 is[x] == is[v] 那也就是这一条链上都可以统计到x上

否则 就要找到中点 , 将中点两边的儿子加到两边。

附加 dfs5 , 清空。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
const int N = 3e5+10;
const int inf = 1e8;
inline int read()
{
	register int x = 0; register char c = getchar();
	while(c < '0' || c > '9') c = getchar();
	while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
	return x;
}
int n , Q , cnt , id , top;
int head[N] , d[N] , f[N][21] , a[N] , dfn[N] , siz[N] , sta[N] , tag[N] , b[N] , is[N] , ans[N] , up[N];
pair<int,int> g[N];
vector<int> ed[N];
struct edge{ int v , nex; } e[N<<1];
inline void add(int u , int v) { e[++cnt].v = v; e[cnt].nex = head[u]; head[u] = cnt; return ; }
inline bool cmp(const int &A , const int &B) { return dfn[A] < dfn[B]; }
inline void addc(int u , int v) { ed[u].push_back(v); return ; }

void dfs(int x , int fa)
{
	dfn[x] = ++id; d[x] = d[fa] + 1; siz[x] = 1;
	for(int i = 1 ; i <= 20 ; ++i) f[x][i] = f[f[x][i-1]][i-1];
	for(register int i = head[x] , v; i ; i = e[i].nex)
	{
		v = e[i].v; if(v == fa) continue;
		f[v][0] = x; dfs(v , x); siz[x] += siz[v];
	}
	return ;
}

int lca(int x , int y)
{
	if(x == y) return x;
	if(d[x] < d[y]) swap(x , y);
	register int i ;
	for(i = 20 ; ~i ; --i) if(d[f[x][i]] >= d[y]&&f[x][i]) x = f[x][i];
	if(x == y) return x;
	for(i = 20 ; ~i ; --i) if(f[x][i] != f[y][i]) x = f[x][i] , y = f[y][i];
	return f[x][0];
}

void build_tree(int k)
{
	sort(a + 1 , a + 1 + k , cmp);
	top = 0; if(a[1] != 1) sta[top = 1] = 1;
	for(int i = 1 ; i <= k ; ++i)
	{
		int x = a[i];
		if(top <= 1) { sta[++top] = x; continue; }
		int p = lca(x , sta[top]);
		if(sta[top] == p) { sta[++top] = x; continue; }
		while(top > 1 && d[sta[top-1]] >= d[p]) addc(sta[top-1] , sta[top]) , top--;
		if(sta[top] != p) addc(p , sta[top]) , sta[top] = p;
		sta[++top] = x;
	}
	while(top > 1) addc(sta[top-1] , sta[top]) , top--;
	return ;
}

void dfs1(int x)
{
	if(tag[x]) g[x] = pair<int,int>{0, x}; else g[x] = pair<int,int>{inf, 0};
	for(int i = 0; i < (int)ed[x].size(); i ++)
	{
		int y = ed[x][i]; dfs1(y);
		g[x] = min(g[x], pair<int,int>{g[y].first + d[y] - d[x], g[y].second});
	}
}

void dfs2(int x , int A , int B)
{
	pair<int,int> p = make_pair(A , B);
	if(p < g[x]) g[x] = p; else A = g[x].first , B = g[x].second;
	for(int i = 0 , v , s = ed[x].size() ; i < s ; ++i)
	{
		v = ed[x][i];
		dfs2(v , A + d[v] - d[x] , B);
	}
	return ;
}

void dfs3(int x)
{
	is[x] = g[x].second; ans[is[x]] += siz[x];
	register int i , j , v , s;
	for(i = 0 , s = ed[x].size() ; i < s ; ++i)
	{
		v = ed[x][i];
		for(j = 20 ; ~j ; --j) if(f[v][j] && d[f[v][j]] > d[x]) v = f[v][j];
		ans[is[x]] -= siz[up[ed[x][i]] = v]; dfs3(ed[x][i]);
	}
	return ;
}

void dfs4(int x)
{
	register int i , v , s , now , t , j;
	for(i = 0 , s = ed[x].size(); i < s ; ++i)
	{
		t = v = ed[x][i]; now = up[v];
		if(is[x] == is[v]) ans[is[x]] += siz[now] - siz[v];
		else
		{
			int H = d[x] + d[is[v]] - g[x].first;
			H = (H & 1) ? ((H + 1) >> 1) : (is[v] < is[x] ? (H >> 1) : ((H >> 1) + 1));
			for(j = 20 ; ~j ; --j) if(f[t][j] && d[f[t][j]] >= H) t = f[t][j];
			ans[is[v]] += siz[t] - siz[v];
			ans[is[x]] += siz[now] - siz[t];
		}
		dfs4(v);
	}
}

void dfs5(int x)
{
	for(int i = 0 , s = ed[x].size() ; i < s ; ++i)
		dfs5(ed[x][i]);
	ed[x].clear(); tag[x] = ans[x] = is[x] = up[x] = 0;
	return ;
}

int main()
{
	n = read();
	register int i , j , k , rt;
	for(i = 1 ; i < n ; ++i)
	{
		int a = read(); int b = read();
		add(a , b); add(b , a);
	}
	dfs(1 , 0);
	Q = read();
	for(i = 1 , k ; i <= Q ; ++i)
	{
		k = read();
		for(j = 1 ; j <= k ; ++j) tag[b[j] = a[j] = read()] = 1;
		build_tree(k); rt = sta[1];
		dfs1(rt); dfs2(rt , g[rt].first , g[rt].second);
		dfs3(rt); dfs4(rt);
		for(j = 1 ; j <= k ; ++j) printf("%d " , ans[b[j]]);
		dfs5(rt); puts("");
	}
	return 0;
}
/*
10
2 1
3 2
4 3
5 4
6 1
7 3
8 3
9 4
10 1
5
2
6 1
5
2 7 3 6 9
1
8
4
8 7 10 3
5
2 9 3 5 8
*/
原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12163948.html