1. 程式人生 > 實用技巧 >頹紅警

頹紅警

事實證明,小可愛是最可愛的嚶! ——佚名
現在小可愛在頹遊戲,但是他遇到了一個問題:
小可愛率領的部隊現在面對的是敵軍在這一地區的駐軍,敵國戰爭機器的運作很大程度上依賴指揮,所以敵軍內部是嚴明分級的,就是說,全部敵軍可以看作一棵樹,每隻敵軍部隊(樹上每個節點)有其戰鬥力。你可以對任意敵軍部隊發動進攻,小可愛的部隊有戰鬥力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 ;
}
/*
*/