思路:二分出结束天数 mid,对其 check,得到对于 i 点的最晚合法时间,之后在树上递推向上
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN=1e5+5;
LL a[MAXN];
int b[MAXN],c[MAXN];
vector<int>gra[MAXN];
int lim[MAXN],dp[MAXN];
int N;
bool Chk(int i,int day,int x)
{
// printf("Chk%d %d %d ",i,day,x);
int d=day-x+1;
__int128 h=(__int128) b[i]*d+(__int128)(x+day)*(day-x+1)/2*c[i];
if(c[i]<0)
{
int m=(floor)((double)b[i]-1)/(-c[i]);
// printf("[%d %lld %d]\n",m,b[i],-c[i]);
h=(__int128) b[i]*(m-x+1)+(__int128)(x+m)*(m-x+1)/2*c[i];
h+=(__int128) day-m;
if(m==0) h=d;
}
//printf("%lld %lld\n",(LL)h,a[i]);
h=max(h,(__int128)d);
if(h>=(__int128) a[i]) return true;
return false;
}
void dpfs(int u,int fa)
{
dp[u]=lim[u];
for(int i=0;i<gra[u].size();i++)
{
int v=gra[u][i];
if(v==fa) continue;
dpfs(v,u);
dp[u]=min(dp[u],dp[v]-1);
}
return;
}
bool Check(int x)
{
//printf("Check%d\n",x);
for(int i=1;i<=N;i++)
{
int l=1,r=x,res=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(Chk(i,x,mid)) res=mid,l=mid+1;
else r=mid-1;
}
if(!res) return false;
lim[i]=res;
}
// for(int i=1;i<=N;i++) printf("%d ",lim[i]);
dpfs(1,0);
sort(dp+1,dp+N+1);
if(dp[1]<1) return false;
for(int i=1;i<=N;i++)
{
if(dp[i]<i) return false;
}
// puts("OK!!");
return true;
}
int main()
{
scanf("%d",&N);
for(int i=1;i<=N;i++) scanf("%lld %d %d",&a[i],&b[i],&c[i]);
for(int i=1;i<N;i++)
{
int u,v;
scanf("%d %d",&u,&v);
gra[u].push_back(v);
gra[v].push_back(u);
}
// Chk(1,100,50);
// return 0;
int l=0,r=1e9,ans;
while(l<=r)
{
int mid=(l+r)>>1;
if(Check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}