CF739B Alyona and a tree
CF739B Alyona and a tree
题目描述:
Alyona有一棵有 nn 个节点的树。这棵树的根节点是 11。在每个节点里,Alyona写了一个正整数,在节点 ii 她写了正整数 a_ia**i 。另外,她在这棵树上的每条边上写了一个正整数(不同边上可能有不同的数)。
让我们定义 dist(v,u)dis**t(v,u) 作为从 vv 到 uu 的简单路径上的边权和。
当且仅当 uu 在 vv 的子树中并且 dist(v,u)\leq a_udis**t(v,u)≤a**u,顶点 vv 控制顶点 u(v!=u)u(v!=u) 。
Alyona想在某些顶点定居。为了做到这件事,她想知道在每个节点 vv 能控制几个节点。
输入格式:
第一行包含一个整数 n (1\leq n\leq 2\times 10^5)n(1≤n≤2×105)
第二行有 nn 个整数 a_1,a_2,\ldots,a_n(1\leq a_i\leq 10^9)a1,a2,…,a**n(1≤a**i≤109) ,作为节点 ii 的数。
下面的 n-1n−1 行,每行有两个整数。第 ii 行包含整数 p_i,w_i(1\leq p_i\leq n,1\leq w_i\leq 10^9)p**i,w**i(1≤p**i≤n,1≤w**i≤109) ,分别为节点 i+1i+1 的在树上的父节点和 p_ip**i 和 (i+1)(i+1) 的边上的数字。
数据保证是个树。
输出格式:
输出 nn 个整数,第 ii 个数为节点 ii 能控制的点数。
样例说明:
在样例中,节点 11 控制了节点 33 ,节点 33 控制节点 55 (注意,这并不代表节点 11 控制了节点 55 )
Translated by @lolte
题解:
不是很难理解题意。一开始想到的是维护距离前缀和,然后对每个点进行深搜,这样的话复杂度是\(O(n^2)\)的。然后想到可以反向维护,一个节点只可能对它所有的祖先节点产生贡献,这样的话复杂度是最优\(O(n\log n)\),最坏\(O(n^2)\)的,还是会被卡。
然后思路断了,但是还是我太菜了,本来想到这,枚举祖先,一定会想到倍增优化枚举,但是本蒟蒻就是没想到。所以严格\(O(n\log n)\)的思路就出来了:树上倍增维护一个点对祖先的贡献,这里可以用一遍DFS来处理,然后用树上差分统计答案。记得开Longlong。
代码:
#include<cstdio>
#define int long long
using namespace std;
const int maxn=2e5+5;
int n;
int a[maxn];
int tot,head[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1];
int fa[maxn][22],dist[maxn],w[maxn],ans[maxn];
//fa[x][k]表示x的2^k辈祖先是谁。
void add(int x,int y,int z)
{
to[++tot]=y;
nxt[tot]=head[x];
val[tot]=z;
head[x]=tot;
}
void dfs1(int x,int f)
{
fa[x][0]=f;
for(int i=1;i<=21;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)
continue;
w[y]=val[i];
dist[y]=dist[x]+w[y];
dfs1(y,x);
}
}
void dfs2(int x)
{
int pos=x;
for(int i=21;i>=0;i--)
if(fa[pos][i] && dist[x]-dist[fa[pos][i]]<=a[x])
pos=fa[pos][i];
ans[fa[pos][0]]--;
ans[fa[x][0]]++;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa[x][0])
continue;
dfs2(y);
ans[x]+=ans[y];
}
}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=2;i<=n;i++)
{
int f,ww;
scanf("%lld%lld",&f,&ww);
add(f,i,ww);
add(i,f,ww);
}
dfs1(1,0);
dfs2(1);
for(int i=1;i<=n;i++)
printf("%lld ",ans[i]);
return 0;
}