P11189 「KDOI-10」水杯降温 题解
TimSwn090306 · · 题解
题目传送门
好题,但是赛时 inf 开太大痛失 56pts。
\tt{Sol.}
发现两种操作并不互相影响,考虑先做吹风操作,再做加热操作。
设第
那么原问题有解的充要条件是:
证明显然。可以通过若干次加热操作将所有点的温度加热到
不难发现,不管进行位于哪个叶子节点上的吹风操作,根节点的
现在来考虑吹风操作怎么做。
设
最好情况下
设最终使
那么有
此时
然后二分答案
总时间复杂度
\tt{Code.}
#include <bits/stdc++.h>
#define fin(str) freopen(str,"r",stdin)
#define fout(str) freopen(str,"w",stdout)
#define ll long long
#define NO return (void)printf("Shuiniao\n")
#define YES return (void)printf("Huoyu\n")
using namespace std;
const int maxn=2e5+5;
const ll inf=1e12;//qwqwqwqwqwq
int type,T;
int n,fa[maxn];
vector <int> G[maxn];
ll a[maxn],f[maxn];
int flag_imp;
inline void DP(int x){
if (flag_imp) return ;
if (!G[x].size()){
f[x]=inf;
return ;
}
for (int i=0;i<G[x].size();i++){
int v=G[x][i];
DP(v);
f[x]+=f[v];
}
ll l=0,r=f[x];
while (l<=r){
ll mid=(l+r)>>1;
int flag=true;
ll sum=0;
for (int i=0;i<G[x].size();i++){
int v=G[x][i];
if (a[v]-f[v]>a[x]-mid){
flag=false;
break;
}
sum+=max(0ll,a[v]-(a[x]-mid));
}
if (flag && sum<=mid) l=mid+1;
else r=mid-1;
}
f[x]=r;
if (f[x]<0) flag_imp=true;
}
inline void solve(){
scanf("%d",&n);
for (int i=1;i<=n;i++) G[i].clear();
for (int i=2;i<=n;i++){
scanf("%d",&fa[i]);
G[fa[i]].push_back(i);
}
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
for (int i=2;i<=n;i++){
if (a[fa[i]]<a[i]) NO;
}
for (int i=1;i<=n;i++) f[i]=0;
flag_imp=false;
DP(1);
if (flag_imp) NO;
if (f[1]<a[1]) NO;
YES;
}
int main(){
// fin("water7.in");
// fout("water.out");
scanf("%d%d",&type,&T);
while (T--) solve();
return 0;
}