CF739B Alyona and a tree题解
题目描述:
Alyona有一棵有 n 个节点的树。这棵树的根节点是 1。在每个节点里,Alyona写了一个正整数,在节点 i 她写了正整数\(a_{i}\)。 另外,她在这棵树上的每条边上写了一个正整数(不同边上可能有不同的数)。
让我们定义 dist(v,u) 作为从 v 到 u 的简单路径上的边权和。
当且仅当 u 在 v 的子树中并且\(dist(v,u)\leq a_u\),顶点 v 控制顶点 u(v!=u)u 。
Alyona想在某些顶点定居。为了做到这件事,她想知道在每个节点 v 能控制几个节点。
我们考虑算每个节点对那些点有贡献,
显然,它能产生贡献的点是一条链,
所以,倍增找链的顶端节点,
一条链的修改,且最后询问???
树上差分就行了,
所以??
上代码:
#include
#define ll long long
using namespace std;
const int N=2e5+6;
int n,m,t,t1,t2,cnt=0,d[N],a[N],book[N],ans[N],head[N],f[N][21];
ll g[N][21],sum=0;
struct edge{int nxt,to,w;}e[N];
inline void add(int u,int v,int w){e[++cnt].nxt=head[u],e[cnt].to=v,e[cnt].w=w,head[u]=cnt;}
inline int read(){
int T=0,F=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
return F*T;
}
void dfs(int x){
t=x,sum=0;
for(int i=1;i<=20;++i) g[x][i]=g[x][i-1]+g[f[x][i-1]][i-1],f[x][i]=f[f[x][i-1]][i-1];
for(int i=20;i>=0;--i) if(a[x]>=sum+g[t][i]) sum+=g[t][i],t=f[t][i];
if(!t&&x!=1) t=1;
++book[x],--book[t];
for(int i=head[x];i;i=e[i].nxt) f[e[i].to][0]=x,g[e[i].to][0]=e[i].w,d[e[i].to]=d[x]+1,dfs(e[i].to);
}
void dfs2(int x){
for(int i=head[x];i;i=e[i].nxt) dfs2(e[i].to),ans[x]+=ans[e[i].to]+book[e[i].to];
}
int main(){
n=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=2;i<=n;++i) t1=read(),t2=read(),add(t1,i,t2);
d[1]=1,dfs(1),dfs2(1);
for(int i=1;i<=n;++i) printf("%d ",ans[i]);
return 0;
}