P9755 [CSP-S 2023] 种树

题目链接:P9755 [CSP-S 2023] 种树


对于某一颗树来说,其高度

f(x)=i=1rmax(bx+cxi,1)

考虑 cx>0 的情况:

f(x)=i=1rbx+cxi

化简为:

f(x)=i=1rbx+i=1rcxi

观察到

i=1rcxi

为一个等差数列

原式最后为

f(x)=rl+1bx+cx(r+l)(rl+1)2


接下来考虑 cx=0 的情况

f(x)=i=1rmax(bx,1)

由于 bx>=1

f(x)=i=1rbx

即时间 tx=axbx


考虑当 cx<0 的情况:

tmax 为使 bx+cxtmax>=1 的最大值

即: tmax<=(1bx)cx

接下来分三种情况:

tmax<l 时: f(x)=rl+1

tmax>r 时: f(x)=(rl+1)bx+cx(r+l)(rl+1)2

l<=tmax<=r 时:
f(x)=(tmaxl+1)bx+cx(tmax+l)(tmaxl+1)2+(rtmax)


那么接下来就是重点了

二分时考虑将于这个点相关联的路径走一遍,也就是说从它的祖先节点到它是否都满足条件

我们可以里利用一遍dfs来求

接着考虑用栈来存这个路径

除此之外我们应当令 tx 为使这个节点最晚满足的时间

再排序一遍,根据时间来进行二分


详细代码如下:

#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;
}
posted @   0tAp  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示