P9755 [CSP-S 2023] 种树 题解
二分答案(最少天数)。
下面是判断一个天数是否满足条件:
对每个点二分出最晚的种树时间。
\(\tt Dfs\) 一遍:对于每个点,遍历完子树后将其的最晚种树时间与 \(\text{儿子的最晚种树时间}-1\) 取最小值,得到的就是真实的最晚种树时间。
最后只要对于每个 \(i(1\le i\le n)\),最晚种树时间不超过 \(i\) 的点的个数 \(\le i\) 就可以了,做一遍前缀和即可。注意,取最小值以后最晚种树时间可能 \(\le0\),要特判。求一段时间内的生长高度时需要用 __int128
,会爆 long long
。
时间复杂度 \(O(n\log V\log n)\),常数很小。
参考代码:
#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){
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);
}
}
bool check(int mx){
rep(i,1,n){
if(a[i]>get(1,mx,c[i],b[i]))return 0;
int l=1,r=n;
while(l<r){
int mid=(l+r+1)>>1;
if(a[i]<=get(mid,mx,c[i],b[i]))l=mid;
else r=mid-1;
}
if(i==1)l=1;
p[i]=l;
}
dfs(1,0);
rep(i,1,n)ct[i]=0;
rep(i,1,n){
if(p[i]<1)return 0;
ct[p[i]]++;
}
rep(i,1,n){
ct[i]+=ct[i-1];
if(ct[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;
while(l<r){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<l;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!