1.题目大意:给出一棵树,现在如果对一个节点轰炸一次,那么和它距离不超过2的节点也会被波及。现在有q(q<=7e5)次轰炸,问每次被轰炸的后此次轰炸的节点目前为止被轰炸多少次
2.很明显想到暴力dfs,但是如果只有树的深度只有2层而且所有子节点均连接在根节点,轰炸Q次根节点,时间复杂度达到了O(n2)。必须想其他方法,不难发现对于树上的某个点,我们只需要考虑它的儿子,孙子,父亲,兄弟,爷爷这五个相关节点,对树dfs后,首先肯定能求出所有节点的父节点,设ans[i][j](j=0,1,2),其中0代表该节点本身的影响,1代表它对儿子的影响,2代表它对孙子的影响。因为每个节点的父节点确定,那么我们每次轰炸一个节点后,更新它对儿子和孙子的影响,更新它对父亲以及父亲的兄弟的影响,更新它对爷爷的影响,那么:
总影响=本身的影响+其父节点对儿子的影响+其祖父节点对孙子的影响
3.为什么不考虑儿子和孙子对它的影响?因为儿子和孙子对它的影响已经计算在它本身影响中。为什么增加轰炸后它本身的影响?因为我们一旦增加了父亲对儿子的影响,它本身也作为父亲的儿子被更新
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn=8e5+10;
vector<int> G[maxn];
int ans[maxn][3];
int fa[maxn];
void dfs(int u,int v){
fa[v]=u;
for(int i=0;i<G[v].size();i++){
if(G[v][i]!=u) dfs(v,G[v][i]);
}
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,q,a,b,x;
cin>>n>>q;
for(int i=1;i<n;i++) {
cin>>a>>b;
G[a].push_back(b);
G[b].push_back(a);
}
dfs(0,1);
while(q--) {
cin>>x;
ans[x][1]++; //儿子
ans[x][2]++; //儿子的儿子
ans[fa[x]][0]++; //父亲
ans[fa[x]][1]++; //父亲的儿子——兄弟 (包括它自己!)
ans[fa[fa[x]]][0]++; //父亲的父亲
cout<<ans[x][0]+ans[fa[x]][1]+ans[fa[fa[x]]][2]<<endl;
}
return 0;
}