![]()
![]()
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define mxn 100003
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
using namespace std;
int n,p[mxn],d[mxn],ct[mxn];
ll a[mxn],b[mxn],c[mxn];
vector<int>g[mxn];
bool v[mxn];
inline __int128 get(ll i,ll n,__int128 a,__int128 b)
//从第i天到第N天,按试题的规定,某棵树能长多高
// b[i]+x*C[i],其中a代表c[i],b代表b[i]
{
if(a<0)
{
ll d=min((b-a-1)/(-a),(__int128)n+1);
if(d<=i)
return n-i+1;
return n-d+1+(d-i)*b+(d-1+i)*(d-i)/2*a;
}
return (n+i)*(n-i+1)/2*a+b*(n-i+1);
}
void dfs(int x,int fa)
{
for(int i:g[x])
if(i!=fa)
{
dfs(i,x);
p[x]=min(p[x],p[i]-1);
//对于第x个树来说,p[x]代表它在第几天就应该种上来
//但由于只有种下x,才能种它的子结点,于是取它自己的时间与子结点时间-1的较小值
}
}
bool check(int mx)
{
rep(i,1,n)
//算出每棵树,最晚应该在哪个时间点来种
{
int l=1,r=n;
//二分找第i棵树最迟种下来的时间,R的初值必须为n
//如果设为mx的话,会过界的
int ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(a[i]<=get(mid,mx,c[i],b[i]))
ans=max(ans,mid),l=mid+1;
else
r=mid-1;
}
if (ans==0) return 0;
if(i==1)
ans=1;
p[i]=ans;
}
// for(int i=1;i<=n;i++)
// cout<<i<<" "<<p[i]<<endl;
dfs(1,0);
//修正每个点最晚的种树时间,修正后p数组的值会控制在1到N之间
rep(i,1,n)
ct[i]=0;
rep(i,1,n)
{
if(p[i]<1) //这句必须要加上,因为有可能修正后p[1]变成了0
return 0;
ct[p[i]]++; //在第p[i]个时间要种树的行为,要执行多少次
}
rep(i,1,n)
//枚举时间
{
ct[i]+=ct[i-1]; //统计一共要种多少棵树
if(ct[i]>i) //前i个时间只能种i棵树
return 0;
}
return 1;
}
signed main(){
scanf("%d",&n);
rep(i,1,n)
scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
for(int i=1,x,y;i<n;++i)
{
scanf("%d%d",&x,&y);
g[x].pb(y),g[y].pb(x);
}
int l=n,r=1e9;
int ans=1e9;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))
ans=min(ans,mid),r=mid-1;
else l=mid+1;
}
cout<<ans<<endl;
return 0;
}
![]()
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
using namespace std;
const int N = 1e5, E = N << 1;
const long long Max = 1e9;
typedef pair<long long, int> pir;
int n;
long long a[N + 5], b[N + 5], c[N + 5], zero[N + 5];
int head[N + 5], to[E + 5], nxt[E + 5], tot = 1;
void add_edge(int u, int v)
{
tot++;
to[tot] = v;
nxt[tot] = head[u];
head[u] = tot;
return ;
}
void add(int u, int v)
{
add_edge(u, v);
add_edge(v, u);
return ;
}
long long d[N + 5];//limit
int sz[N + 5];
void calc_d(int u, long long ans)
{
long long l = 1, r = n;
d[u] = -1ll;
while (l <= r)
{
long long mid = (l + r) >> 1;
__int128 sum = 0, one = 1;
if (c[u] >= 0)
sum = one * (ans - mid + 1) * b[u]
+ one * (mid + ans) * (ans - mid + 1) / 2 * c[u];
else
{
if (mid > zero[u])
sum = ans - mid + 1;
else if (ans > zero[u])
sum = one * (zero[u] - mid + 1) * b[u]
+ one * (mid + zero[u]) * (zero[u] - mid + 1) / 2 * c[u]
+ ans - zero[u];
else
sum = one * (ans - mid + 1) * b[u]
+ one * (mid + ans) * (ans - mid + 1) / 2 * c[u];
}
if (one * a[u] <= sum)
{
d[u] = mid;
l = mid + 1;
}
else
r = mid - 1;
}
return ;
}
int fa[N + 5], in[N + 5];
void dfs(int u, int father)
{
fa[u] = father;
in[father]++;
for (int i = head[u]; i; i = nxt[i])
{
int v = to[i];
if (v == father)
continue;
dfs(v, u);
}
return ;
}
priority_queue<pir> q;
int seq[N + 5];
bool check(long long ans)
{
for (int i = 1; i <= n; i++)
{
calc_d(i, ans);
if (d[i] < 0)
return false;
}
dfs(1, 0);
for (int i = 1; i <= n; i++)
{
if (in[i] == 0)
q.emplace(d[i], i);
}
for (int T = n; T > 0; T--)
{
int u = q.top().second;
q.pop();
seq[T] = u;
if (fa[u])
{
in[fa[u]]--;
if (in[fa[u]] == 0)
q.emplace(d[fa[u]], fa[u]);
}
}
for (int i = 1; i <= n; i++)
{
if (1ll * i > d[seq[i]])
return false;
}
return true;
}
int main()
{
// freopen("tree.in", "r", stdin);
// freopen("tree.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lld%lld%lld", a + i, b + i, c + i);
if (c[i] < 0)
zero[i] = (1ll - b[i]) / c[i];
}
for (int i = 1, u, v; i < n; i++)
{
scanf("%d%d", &u, &v);
add(u, v);
}
long long l = 1, r = Max, ans = 0;
while (l <= r)
{
long long mid = (l + r) >> 1;
if (check(mid))
{
ans = mid;
r = mid - 1;
}
else
l = mid + 1;
}
printf("%lld\n", ans);
return 0;
}