测评会员优惠活动进行中 · 开通 VIP,有效期内测评不限次 VIP 优惠中 · 测评不限次 立即查看

A35528. 种树(tree)

填空题 困难

题目描述

种树(tree)

题目描述

你是一个森林养护员,有一天,你接到了一个任务:在一片森林内的地块上种树,并养护至树木长到指定的高度。

森林的地图有n片地块,其中1号地块连接森林的入口。共有n−1条道路连接这些地块,使得每片地块都能通过道路互相到达。最开始,每片地块上都没有树木。

你的目标是:在每片地块上均种植一棵树木,并使得i号地块上的树的高度生长到不低于ai米。

你每天可以选择一个未种树且与某个已种树的地块直接邻接(即通过单条道路相.连)的地块,种一棵高度为0米的树。如果所有地块均已种过树,则你当天不进行任何操作。特别地,第1天你只能在1号空地种树。

对每个地块而言,从该地块被种下树的当天开始,该地块上的树每天都会生长一定的高度。由于气候和土壤条件不同,在第x天,i号地块上的树会长高max(bi+x∗ci,1)

米。注意这里的x是从整个任务的第一天,而非种下这棵树的第一天开始计算。

你想知道:最少需要多少天能够完成你的任务?

输入格式

从文件tree.in中读入数据。

输入的第一行包含一个正整数n,表示森林的地块数量。

接下来n行:每行包含三个整数ai,bi,ci,分别描述一片地块,含义如题目描述中所述。

接下来n−1行:每行包含两个正整数ui,vi,表示一条连接地块ui和vi的道路。

输出格式

输出到文件tree.out中。

输出一行仅包含一个正整数,表示完成任务所需的最少天数。

样例1输入

4

12 1 1

2 4 ‐1

10 3 0

7 10 ‐2

1 2

1 3

3 4

样例1输出

1 5

样例1解释

第1天:在地块1种树,地块1的树木长高至2米。

第2天:在地块3种树,地块1,3的树木分别长高至5,3米。

第3天:在地块4种树,地块1,3,4的树木分别长高至9,6,4米。

第4天:在地块2种树,地块1,2,3,4的树木分别长高至14,1,9,6米。

第5天:地块1,2,3,4的树木分别长高至20,2,12,7米。

样例2

见选手目录下的tree/tree2.in与tree/tree2.ans。

样例3

见选手目录下的tree/tree3.in与tree/tree3.ans。

样例4

见选手目录下的tree/tree4.in与tree/tree4.ans。

数据范围

对于所有测试数据有:1≤n≤105,1≤ai≤1018,1≤bi≤109,0≤|ci|≤109,1≤ui,vi≤n。保证存在方案能在109天内完成任务

特殊性质A:对于所有1≤i≤n,均有ci=0;

特殊性质B:对于所有1≤i<n,均有ui=i,vi=i+1;

特殊性质C:与任何地块直接相连的道路均不超过2条;

特殊性质D:对于所有1≤i<n,均有ui=1。

参考答案

#include<bits/stdc++.h> using namespace std; int n,head[100010],tot,F[100010]; bool v[100010]; vector<pair<int,int> > q; struct node { int to,nex; } edge[200000]; struct node1 { long long a,b,c,t; } a[100010]; void add(int x,int y) { edge[++tot].nex=head[x]; edge[tot].to=y; head[x]=tot; } bool Check(int id,int l,int r) { if(a[id].c>=0) { __int128 h=(__int128)(a[id].b+l*a[id].c+a[id].b+r*a[id].c)*(r-l+1)/2; if(h>=a[id].a) return 1; return 0; } if(l>(1-a[id].b)/a[id].c) { if(r-l+1>=a[id].a) return 1; return 0; } if(r<=(1-a[id].b)/a[id].c) { __int128 h=(__int128)(a[id].b+l*a[id].c+a[id].b+r*a[id].c)*(r-l+1)/2; if(h>=a[id].a) return 1; return 0; } int t=(1-a[id].b)/a[id].c; __int128 h=(__int128)(a[id].b+l*a[id].c+a[id].b+t*a[id].c)*(t-l+1)/2+r-t; if(h>=a[id].a) return 1; return 0; } int work(int id,int x) { int l=0,r=x; while(l+1<r) { int mid=(l+r)/2; if(Check(id,mid,x)) l=mid; else r=mid; } if(Check(id,r,x)) return r; return l; } bool check(int x) { q.clear(); for(int i=1;i<=n;i++) { int jl=work(i,x); if(jl==0) return 0; q.push_back(make_pair(jl,i)); } sort(q.begin(),q.end()); memset(v,0,sizeof v); v[0]=1; int now=0; for(int i=0;i<q.size();i++) { int id=q[i].second; while(!v[id]) { now++; v[id]=1; id=F[id]; } if(now>q[i].first) return 0; } return 1; } void dfs(int x,int fa) { F[x]=fa; for(int i=head[x];i;i=edge[i].nex) { if(edge[i].to==fa) continue; dfs(edge[i].to,x); } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld%lld%lld",&a[i].a,&a[i].b,&a[i].c); for(int i=1;i<n;i++) { int U,V; scanf("%d%d",&U,&V); add(U,V); add(V,U); } dfs(1,0); int l=1,r=1e9; while(l+1<r) { int mid=(l+r)/2; if(check(mid)) r=mid; else l=mid; } if(check(l)) printf("%d",l); else printf("%d",r); return 0; }
上一题 下一题