每个人从1节点走回自己家
一定是前一段路的心情好(可能前一段路长为0),后一段路心情差
我们的难点在哪里?
在于有很多个人,我们不能确定每个人在哪个节点心情开始变差的
但其实我们是可以大概确定的
Ⅰ.考虑叶子节点
对于一个叶子节点w来说
能到达w的都是家在w的,设这些人到达时有x个人心情好,y个人心情产
{x+y=pwx−y=hw
所以x是(pw+hw)/2, y是pw−x
其中(pw+hw)应该是偶数
Ⅱ.考虑非叶子节点k
这一步其实就是由叶子节点往上推的
k的最少开心人数是所有子节点开心人数相加,记作dp[k][1]
k的最大不开心人数是所有子节点不开心人数和+pk,记作dp[k][2]
至于为啥加pk......因为这pk个人在k节点可能开心,也可能不开心,若都不开心那么人数就最大嘛...
那么当前经过这个点的人是sumn=dp[k][1]+dp[k][2]
由Ⅰ知sumn必须是偶数,那么可以解得k节点有x人心情好,y人心情差
这样我们解得x=(sumn+hk)/2,y=sumn−x
我再重申一下
dp[k][1]是最少开心得人数
因为子节点开心得人在上一个节点一定开心(只能由开心->不开心)
但是可能还存在一些人在k节点开心,但是跑到子节点就不开心了
所以这里应该满足x>=dp[k][1]
判断完之后,由于k点的开心,不开心人数被计算出来了,那么
dp[k][1]=x,dp[k][2]=y,然后继续向上推
然后对任意一个节点w满足经过w的总人数>abs(hw),比较显然
然后?然后就开始dfs啊!!
觉得我讲的不好可以在评论区骂我
觉得我讲的好可以在评论区夸我
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
int n,t,dp[maxn][3],flag,h[maxn],p[maxn],m;
vector<int>vec[maxn];
void dfs(int u,int fa)
{
if( vec[u].size()==1&&u!=1 )//到达叶子节点
{
if( p[u]<abs(h[u]) ) flag=0;
if( ( h[u]+p[u] )%2==1 ) flag=0;
dp[u][1]=( h[u]+p[u] )/2;//开心的人数 x
dp[u][2]=p[u]-dp[u][1];//不开心的人数y
return;
}
for(int i=0;i<vec[u].size();i++)
{
int v=vec[u][i];
if( v==fa ) continue;
dfs(v,u);
dp[u][1]+=dp[v][1];//开心的人数至少有这么多
dp[u][2]+=dp[v][2];//不开心的人数
}
dp[u][2]+=p[u];
//dp[u][1]+dp[u][2]是总人数
int sumn=dp[u][1]+dp[u][2];
int x=( sumn+h[u] )/2;//该层应该开心的人数
int y=( sumn-x );//该层不开心的人数
if( sumn<abs(h[u]) ) flag=0;
if( (sumn+h[u])%2==1 ) flag=0;
if( x<dp[u][1] ) flag=0;
dp[u][1]=x,dp[u][2]=y;
}
signed main()
{
cin >> t;
while( t-- )
{
flag=1;
cin >> n >> m ;
for(int i=1;i<=n;i++) scanf("%lld",&p[i]);
for(int i=1;i<=n;i++) scanf("%lld",&h[i]);
for(int i=1;i<n;i++)
{
int l,r;
scanf("%lld%lld",&l,&r);
vec[l].push_back(r);
vec[r].push_back(l);
}
dfs(1,0);
if( flag ) cout << "YES\n";
else cout << "NO\n";
for(int i=1;i<=n;i++)
{
dp[i][1]=dp[i][2]=0;
vec[i].clear();
}
}
}
一起加油努力啊~