1. 程式人生 > 其它 >CodeForces 1436 D. Bandit in a City 二分+卡常

CodeForces 1436 D. Bandit in a City 二分+卡常

技術標籤:# 題解dfs二分法

CodeForces 1436 D. Bandit in a City 二分+卡常

題目大意:

給定一個 n n n 個節點的樹,樹的根節點一定是 1 1 1 ,每個節點都有權值 a i a_i ai,每個節點的權值都要往下分配轉移,直到葉子節點,問葉子節點中最大的權值最小是多少.

權值可以任意整數分配,但一定要分完。

思路:

最大最小問題,直接考慮二分,二分節點的最大值, c h e c k check check 就是跑一遍樹,但這題只有 1 s 1s 1s,所以可能卡常

解釋下各陣列的含義:

  • n u m num num 陣列表示當前節點可分配的權值
  • s u m sum sum 陣列表示以當前節點為根的子樹的權值和
  • c n t cnt cnt 陣列表示以當前節點為根的子樹的葉子節點個數

程式碼

#include <bits/stdc++.h>
using namespace std;
#define me(a, b) memset(a, b, sizeof(a))
#define IOS() ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'

typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<
int, int> pii; const int INF = 0x3f3f3f3f; const int maxn = 2e5 + 5; const ll mod = 1e9 + 7; vector<int> G[maxn]; ll sum[maxn]; ll cnt[maxn]; ll num[maxn]; void dfs(const int& u) { if(G[u].empty()) { ++cnt[u]; return ; } ll s = 0; for(const int& v : G[
u]) { dfs(v); cnt[u] += cnt[v]; s += sum[v]; } sum[u] += s; } bool check(const ll& x, const int& u) { ll s = num[u]; bool res = true; for(const int& v : G[u]) { ll d = min(cnt[v]*x - sum[v], s); if(d < 0) return false; s -= d; sum[v] += d; num[v] += d; res = check(x, v); sum[v] -= d; num[v] -= d; if(!res) return false; } return s == 0 || G[u].empty(); } int main() { IOS(); int n; cin >> n; for(int i = 2; i <= n; ++i) { int u; cin >> u; G[u].push_back(i); } for(int i = 1; i <= n; ++i) { cin >> sum[i]; num[i] = sum[i]; } dfs(1); ll ans = 0; ll l = sum[1]/cnt[1], r = sum[1]; while(l <= r) { ll m = l + r >> 1; if(check(m, 1)) { ans = m; r = m-1; } else l = m + 1; } cout << ans << endl; return 0; }

總結:

跑了 982 m s 982ms 982ms,偷雞過。