题目描述
世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
世界树的形态可以用一个数学模型来描述:世界树中有 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
*/