CodeForces 1436 D. Bandit in a City 二分+卡常
阿新 • • 發佈:2020-12-18
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,偷雞過。