P9755 [CSP-S 2023] 种树
对于某一颗树来说,其高度
\[f(x)=\displaystyle\sum_{i=1}^rmax(b_x+c_x*i,1)
\]
考虑 \(c_x>0\) 的情况:
\[f(x)=\displaystyle\sum_{i=1}^rb_x+c_x*i
\]
化简为:
\[f(x)=\displaystyle\sum_{i=1}^rb_x+\sum_{i=1}^rc_x*i
\]
观察到
\[\displaystyle\sum_{i=1}^rc_x*i
\]
为一个等差数列
原式最后为:
\[f(x)=(r-l+1)b_x+c_x\frac{(r+l)(r-l+1)} 2
\]
接下来考虑 \(c_x=0\) 的情况:
\[f(x)=\displaystyle\sum_{i=1}^rmax(b_x,1)
\]
由于 \(b_x>=1\)
\[f(x)=\displaystyle\sum_{i=1}^rb_x
\]
即时间 \(t_x=⌈{\frac {a_x} {b_x}} ⌉\)
考虑当 \(c_x<0\) 的情况:
设 \(t_{max}\) 为使 \(b_x+c_x*t_{max}>=1\) 的最大值
即: \(t_{max}<=\frac {(1-b_x)} {c_x}\)
接下来分三种情况:
当 \(t_{max}<l\) 时: \(f(x)=r-l+1\)
当 \(t_{max}>r\) 时: \(f(x)=(r-l+1)b_x+c_x\frac {(r+l)(r-l+1)} {2}\)
当 \(l<=t_{max}<=r\) 时:
\(f(x)=(t_{max}-l+1)b_x+c_x\frac {(t_{max}+l)(t_{max}-l+1)} {2} + (r-t_{max})\)
那么接下来就是重点了
二分时考虑将于这个点相关联的路径走一遍,也就是说从它的祖先节点到它是否都满足条件
我们可以里利用一遍dfs来求
接着考虑用栈来存这个路径
除此之外我们应当令 \(t_x\) 为使这个节点最晚满足的时间
再排序一遍,根据时间来进行二分
详细代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int128 __int128
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
const int N=1e5+10;
int n;
long long a[N];
int b[N],c[N];
int p[N],t[N];
int h[N],e[N*2],ne[N*2],idx=0;
int fa[N];
bool vis[N];
int top=0;
int stk[N];
bool cmp(int x,int y)
{
return t[x]<t[y];
}
inline void _add_(int a,int b)
{
e[++idx]=b,ne[idx]=h[a],h[a]=idx;
e[++idx]=a,ne[idx]=h[b],h[b]=idx;
}
inline void dfs(int u,int v)
{
fa[u]=v;
for(int i=h[u];i;i=ne[i])
{
if(e[i]!=v)dfs(e[i],u);
}
}
inline int128 f(int128 l,int128 r,int x)
{
if(c[x]>0)
{
return (r-l+1)*b[x]+(r+l)*(r-l+1)/2*c[x];
}
else if(c[x]==0)
{
return (r-l+1)*b[x];
}
else{
int128 t_max=(1-b[x])/c[x];
if(t_max<l)return (r-l+1);
else if(t_max>r)return (r-l+1)*b[x]+(r+l)*(r-l+1)/2*c[x];
else {
return (t_max-l+1)*b[x]+(t_max+l)*(t_max-l+1)/2*c[x]+(r-t_max);
}
}
}
inline bool _cheak_(int r)
{
rep(i,1,n)
{
if(f(1,r,i)<a[i])return false;
int now_l=1,now_r=n;
while(now_l<now_r)
{
int mid=(now_l+now_r+1)>>1;
if(f(mid,r,i)>=a[i])now_l=mid;
else now_r=mid-1;
}
p[i]=i;
t[i]=now_l;
vis[i]=false;
}
sort(p+1,p+n+1,cmp);
int the_day=0;
for(int now_idx=1;now_idx<=n;now_idx++)
{
int now=p[now_idx];
top=0;
while(!vis[now]){
stk[++top]=now;
vis[now]=true;
now=fa[now];
}
while(top)
{
the_day++;
if(t[stk[top]]<the_day)return false;
top--;
}
}
return true;
}
int main()
{
scanf("%d",&n);
rep(i,1,n)
{
scanf("%lld%d%d",&a[i],&b[i],&c[i]);
}
rep(i,1,n-1)
{
int u,v;
scanf("%d%d",&u,&v);
_add_(u,v);
}
dfs(1,0);
vis[0]=true;
int l=n,r=1e9;
while(l<r)
{
int mid=(l+r)>>1;
if(_cheak_(mid))r=mid;
else l=mid+1;
}
printf("%d",l);
return 0;
}

浙公网安备 33010602011771号