P9755 [CSP-S 2023] 种树 题解
upd on 2023.11.20:增加细节说明。
刚开始浪费太多时间了,导致赛时没调出来,有点火大。
如果一开始没有头绪的话可以先看一下特殊性质,链是直接贪心。
考虑一下菊花,发现直接贪心是不可做的,但是发现树的高度随时间增大而增大,可以用二分转化为判定性问题解决。
对于任意的树来说,参考菊花,考虑二分出时间,转化为判定性问题。可以通过求根公式或者再套一层二分求出每个点最晚被种树的时间。然后贪心的按照求出的每个点最晚植树的时间
这样的话复杂度是
注意有些地方可能会爆 long long。
代码里的二分写法可能和其他的不是很一样。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define i128 __int128
#define vi vector<int>
#define eb emplace_back
#define pii pair<int, ll>
#define fi first
#define se second
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
bool Mbe;
mt19937_64 rng(35);
constexpr int N = 1e5 + 10;
int n;
int b[N], c[N], fa[N];
ll a[N];
int head[N], cnt_e;
struct edge{
int v, nxt;
} e[N << 1];
void adde(int u,int v){
++cnt_e, e[cnt_e].v = v, e[cnt_e].nxt = head[u], head[u] = cnt_e;
}
void dfs(int u, int ff){
fa[u] = ff;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if(v == ff) continue;
dfs(v, u);
}
}
int stk[N], tp, vis[N], id[N];
ll t[N];
i128 calc(int i, int tl, int tr, int mxc) {
if(mxc < tl) return tr - tl + 1;
if(mxc > tr) return (tr - tl + 1) * 1ll * b[i] + (tr - tl + 1) * ((i128)(tl + tr)) / 2 * c[i];
return (mxc - tl + 1) * 1ll * b[i] + (mxc - tl + 1) * ((i128)tl + mxc) / 2 * c[i] + tr - mxc;
}
bool check(int tim){
for(int i = 1; i <= n; ++i) {
if(c[i] < 0) {
int mxc = ((b[i] - 1) / abs(c[i]));
int l = 1, r = n;
while(l <= r) {
int mid = (l + r) >> 1;
if(calc(i, mid, tim, mxc) >= ((i128)a[i])) l = mid + 1;
else r = mid - 1;
}
t[i] = r;
} else if(!c[i]) {
t[i] = tim - (a[i] + b[i] - 1) / b[i] + 1;
} else {
int l = 1, r = n;
while(l <= r) {
int mid = (l + r) >> 1;
if(b[i] * 1ll * (tim - mid + 1) + (tim + mid) * ((i128)tim - mid + 1) * c[i] / 2 >= ((i128)a[i]))
l = mid + 1;
else r = mid - 1;
}
t[i] = r;
}
if(t[i] <= 0) return 0;
}
for(int i = 1; i <= n; ++i) id[i] = i, vis[i] = 0;
sort(id + 1, id + n + 1, [](int a, int b) {
return t[a] < t[b];
});
int now = 0; tp = 0;
for(int i = 1; i <= n; ++i) {
int u = id[i];
for(; !vis[u]; u = fa[u]) vis[stk[++tp] = u] = 1;
while(tp)
if(t[stk[tp--]] < ++now)
return 0;
}
return 1;
}
bool Med;
int main(){
fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
ios :: sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n;
for(int i = 1; i <= n; ++i) cin >> a[i] >> b[i] >> c[i];
for(int i = 1, u, v; i < n; ++i) cin >> u >> v, adde(u, v), adde(v, u);
dfs(1,0);
vis[0] = 1;
int l = n, r = 1e9;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
cout << l << "\n";
cerr << TIME << "ms\n";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具