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)\)
程式碼:
#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;
}