颓红警

事实证明,小可爱是最可爱的嘤! ——佚名
现在小可爱在颓游戏,但是他遇到了一个问题:
小可爱率领的部队现在面对的是敌军在这一地区的驻军,敌国战争机器的运作很大程度上依赖指挥,所以敌军内部是严明分级的,就是说,全部敌军可以看作一棵树,每只敌军部队(树上每个节点)有其战斗力。你可以对任意敌军部队发动进攻,小可爱的部队有战斗力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 − d i s [ i , j ] 2 > 0 p - dis[i , j]^2 > 0 pdis[i,j]2>0 , 也就是如果用深度表示dis , 那么就是 ( d i s [ j ] − d i s [ i ] ) 2 < p ( dis[j] - dis[i] )^2 < p (dis[j]dis[i])2<p , 就是 d i s [ j ] − d i s [ i ] < p dis[j] - dis[i] <\sqrt p dis[j]dis[i]<p , 也就是说对于i来说它的祖先节点只有距离它 p \sqrt p p 以内的才会对i产生影响。
5. 那么也就是说对于i来说,我们只关心距离当前点距离为 p \sqrt p p 的点,大于这个的我们都不关心,这个可以用滑动窗口来维护
6. 那么维护的内容是什么呢。 p − d i s [ i , j ] 2 = p − ( d i s ( j ) − d i s ( i ) ) 2 = p − d i s ( i ) 2 − d i s ( j ) 2 + 2 ∗ d i s ( i ) ∗ d i s ( j ) p - dis[i , j] ^ 2 \\ = p - (dis(j) - dis(i)) ^ 2 \\ = p - dis(i) ^ 2 - dis(j) ^ 2+ 2 * dis(i)*dis(j) pdis[i,j]2=p(dis(j)dis(i))2=pdis(i)2dis(j)2+2dis(i)dis(j)
可以发现对于一个滑动窗口里面, d i s [ j ] dis[j] dis[j]是需要枚举的, i i i j j j的祖先节点,那么我们需要维护的也就是区间 d i s [ i ] 2 , d i s [ i ] dis[i] ^ 2 , dis[i] dis[i]2,dis[i] , 还有 c n t ∗ ( p − d i s [ i ] 2 ) cnt * (p - dis[i] ^ 2) cnt(pdis[i]2) ,这个 c n t cnt 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 ;
}
/*
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值