题目链接:https://www.nowcoder.com/acm/contest/72/C
flag:思维题
*自己没有想到,一直觉得是道树分治题!其实是道查询可以为O(1)的好题!
* 利用dfs将无根树转化为有根树! 记录一个结点波及它的儿子和孙子的次数,和自己受波及的次数用sum[i][3]来记录!
*一个结点i被轰炸,危害等价于父亲的全部儿子受损一次(自己+其它同父兄弟(距离为2))sum[fa[i]][1]++、
父亲(sum[fa[i]][0]++)和i的全部儿子受损一次(距离i为1)、父亲的父亲(sum[fa[fa[i]]][0]++)和全部
孙子受损一次(sum[i][2]++)(距离为2);
*而一个点i的受损次数等于 : sum[i][0]+sum[fa[i]][1]+sum[fa[fa[i]]][2];
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <math.h>
#define Size 750010
using namespace std;
vector <int>V[Size];
int sum[Size][3]={0};
int fa[Size];
int a,b;
void dfs(int rt){
for(int i=0;i<V[rt].size();++i){
if(V[rt][i]==fa[rt])continue;
fa[V[rt][i]]=rt;
dfs(V[rt][i]);
}
}
int Modify(int rt){
if(rt==1) {sum[rt][0]++;sum[rt][1]++;sum[rt][2]++;}
else {sum[fa[fa[rt]]][0]++;sum[fa[rt]][0]++;sum[fa[rt]][1]++;sum[rt][1]++;sum[rt][2]++;}
return (rt==1)?sum[rt][0]:(sum[rt][0]+sum[fa[rt]][1]+sum[fa[fa[rt]]][2]);
}
int main(){
int N,Q;
scanf("%d%d",&N,&Q);
for(int i=1;i<N;++i){
scanf("%d%d",&a,&b);
V[a].push_back(b);
V[b].push_back(a);
}
fa[1]=0;
dfs(1);
while(Q--){
scanf("%d",&a);
printf("%d\n",Modify(a));
}
return 0;
}