事实证明,小可爱是最可爱的嘤! ——佚名
现在小可爱在颓游戏,但是他遇到了一个问题:
小可爱率领的部队现在面对的是敌军在这一地区的驻军,敌国战争机器的运作很大程度上依赖指挥,所以敌军内部是严明分级的,就是说,全部敌军可以看作一棵树,每只敌军部队(树上每个节点)有其战斗力。你可以对任意敌军部队发动进攻,小可爱的部队有战斗力p,意味着他的每次进攻将使得被进攻的这支部队的战斗力减少p,对上级指挥系统的打击同时会影响其下级部队。具体来说,当他对点i发动进攻,部队i的战力减少p的同时,对于其子树内点j,部队j的战力减少Max(0,p−dis(i,j)2)(dis(i,j)表示点i,j间简单路径的长度)。如果某支部队战力小于0,那么这支部队就被消灭了,一支部队被消灭不会改变敌军编制(即这棵树的结构不会改变)。
小可爱想知道,你的部队最少发动几次进攻,才能全歼敌军
由于小可爱还要爆手速发展自己实力,所以把这个问题交给了你。
小可爱因为太可爱了,所以受到了一些限制——只有在一个部队的祖先节点都被歼灭之后才能发动进攻去打它,否则它就会被这个部队的祖先节点攻击,这是他不愿意经历的。
1. 树形结构 ‘
2. 只能从上到下进行操作
3. 每个节点值小于0的时候才不可以对其进行操作
4. 1....i - 1中对i会产生影响的,只有令(p - dis[i , j]^2 > 0) , 也就是如果用深度表示dis , 那么就是(( dis[j] - dis[i] )^2 < p) , 就是(dis[j] - dis[i] <sqrt p), 也就是说对于i来说它的祖先节点只有距离它(sqrt p)以内的才会对i产生影响。
5. 那么也就是说对于i来说,我们只关心距离当前点距离为(sqrt p)的点,大于这个的我们都不关心,这个可以用滑动窗口来维护
6. 那么维护的内容是什么呢。$$p - dis[i , j] ^ 2 = p - (dis(j) - dis(i)) ^ 2 = p - dis(i) ^ 2 - dis(j) ^ 2+ 2 * dis(i)*dis(j)$$
可以发现对于一个滑动窗口里面,(dis[j])是需要枚举的,(i)是(j)的祖先节点,那么我们需要维护的也就是区间(dis[i] ^ 2 , dis[i]) , 还有(cnt * (p - dis[i] ^ 2)) ,这个(cnt)次数,dfs向下传的时候,就相当于区间加一,将当前点的贡献算一下, 同时需要将那一个上面不需要的一个祖先节点的贡献减掉
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#pragma GCC optimize(3 , "Ofast" , "inline")
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
#define x first
#define y second
#define ls rt << 1
#define rs rt << 1 | 1
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 1e9 + 7;
int cinint(){ int t ; scanf("%d" , &t) ; return t ;}
int cinll(){ll t ;scanf("%lld" , &t) ;return t ;}
ll a[N] , n , p ;
vector<int> v[N] ;
ll size[N] , size1[N] , size2[N] , len , cnt[N] , res[N] , ans = 0 ;
void dfs(int u , int fa , ll d){
if(d > len) {
ll t = d - len ;
size[u] -= cnt[t] ;
size1[u] -= cnt[t] * t ;
size2[u] -= cnt[t] * t * t ;
}
res[u] -= size[u] * (p - d * d) - size2[u] + 2 * size1[u] * d ;
ll pos = 0 ;
if(res[u] >= 0) pos = res[u] / p + 1 , ans += pos ;
cnt[d] = pos ;
for(auto x : v[u]) {
if(x == fa) continue ;
size[x] = size[u] + pos , size1[x] += size1[u] + pos * d , size2[x] += size2[u] + pos * d * d ;
dfs(x , u , d + 1) ;
}
}
int work()
{
n = cinint() , p = cinint() ;
len = sqrt(p) + 1 ;
for(int i = 1; i <= n ;i ++ ) res[i] = cinint() ;
for(int i = 1; i < n ;i ++ ) {
int a = cinint() , b = cinint() ;
v[a].push_back(b) , v[b].push_back(a) ;
}
dfs(1 , 0 , 1) ;
cout << ans << endl ;
return 0 ;
}
int main()
{
work() ;
return 0 ;
}
/*
*/