原题题面:
https://ac.nowcoder.com/acm/contest/33191/B
题目大意:
给定一棵树,对于每一个节点
i
i
i,都有一个距离
d
i
d_i
di,表示
i
i
i向根节点
r
o
o
t
root
root 走
d
i
d_i
di步,沿途都打上标记,求每个节点被标记了多少次
(
0
<
n
<
2
∗
1
0
6
+
1
)
(0<n<2*10^6+1)
(0<n<2∗106+1)
分析:因为数据很大,单纯的暴力肯定不行,此时便可以想到树上差分,将
O
(
d
i
)
O(d_i)
O(di)的复杂度变为
O
(
1
)
O(1)
O(1),此刻,便可以通过这道题了
Tip:
在树上差分,通常会用一个stack,记录沿途的节点
代码:`
#include<bits/stdc++.h>
using namespace std;
const int MXN=2*1e6+7;
int d[MXN],pre[MXN],ch[MXN];
vector<int> g[MXN];
int omg[MXN];
inline int read(){
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9'){
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x;
}
void DFS_1(int u,int fa,int len){
int v; omg[len]=u;
for(int i=0;i<g[u].size();i++){
v=g[u][i];
if(v==fa) continue;
DFS_1(v,u,len+1);
if(d[v]>=len){
ch[v]++;
} else {
ch[v]++;
ch[omg[len-d[v]]]--;
}
}
}
void DFS_2(int u,int fa){
int v;
for(int i=0;i<g[u].size();i++){
v=g[u][i];
if(v==fa) continue;
DFS_2(v,u);
pre[v]+=ch[v];
pre[u]+=pre[v];
}
}
int main(){
int n,x,y;
memset(pre,0,sizeof(pre));
n=read();
for(int i=1;i<n;i++){
x=read(); y=read();
g[x].push_back(y);
g[y].push_back(x);
}
for(int i=1;i<=n;i++){
d[i]=read();
}
DFS_1(1,-1,1);
ch[1]++;
DFS_2(1,-1);
pre[1]+=ch[1];
for(int i=1;i<=n;i++){
printf("%d ",pre[i]);
}
printf("\n");
}