题意:给N个节点的树,Q个询问,初始首都为R节点,1 ≤ N ≤ 100 000, 1 ≤ Q ≤ 50 000,1 ≤ R ≤ N, 每个询问包含两个数S和U,0 ≤ S ≤ 1,1 ≤ U ≤ N,S为0代表将首都更新为U节点,否则,请计算出有多少个节点必须经过U才能到达首都。
思路:先DFS一次记录DFS序和每个节点到根节点的距离和每个节点的祖先节点,那么当首都为U的子树节点时,答案为N-son[U的下一个节点],否则答案为son[U],son为某节点为根节点的儿子数,可由DFS序求得。
# include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+3;
int cnt=0, cnt2=0, n, q, cap, Next[maxn];
int fa[maxn][20], in[maxn], out[maxn], len[maxn];
struct node
{
int v, next;
}edge[maxn<<1];
void add_edge(int u, int v)
{
edge[cnt] = {v, Next[u]};
Next[u] = cnt++;
}
void dfs(int cur, int pre, int d)
{
fa[cur][0] = pre;
len[cur] = d;
for(int i=1; i<20; ++i)
fa[cur][i] = fa[fa[cur][i-1]][i-1];
in[cur] = ++cnt2;
for(int i=Next[cur]; i!=-1; i=edge[i].next)
{
int v = edge[i].v;
if(v==pre) continue;
dfs(v, cur, d+1);
}
out[cur] = cnt2;
}
int main()
{
int t,cas=1,a,b;
scanf("%d",&t);
while(t--)
{
cnt = cnt2 = 0;
memset(Next, -1, sizeof(Next));
printf("Case #%d:\n",cas++);
scanf("%d%d%d",&n,&q,&cap);
for(int i=0; i<n-1; ++i)
{
scanf("%d%d",&a,&b);
add_edge(a, b);
add_edge(b, a);
}
dfs(1,1,0);
while(q--)
{
int op, x;
scanf("%d%d",&op,&x);
if(op==0) cap = x;
else
{
if(x==cap)
printf("%d\n",n);
else if(in[x]<=in[cap] && out[x]>=out[cap])
{
int tmp = len[cap]-len[x]-1;
int now = cap;
for(int i=0; i<20; ++i)
if(tmp>>i&1) now=fa[now][i];
printf("%d\n",n-out[now]+in[now]-1);
}
else
printf("%d\n",out[x]-in[x]+1);
}
}
}
return 0;
}