P9755 [CSP-S 2023] 种树

思路

这道题看到所有c为0,那么所有树的生长时间就是确定的,那么就可以贪心的把生长时间长的先种上。
那么对于c不为0,我们考虑二分答案,二分完答案后,我们考虑对于每个树把他最晚种上的合法时间算出来,然后按照上面的贪心做就做完了。
不要写了一个函数不调用啊

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll a[100005], b[100005], c[100005];
inline __int128 sol(ll x, ll l, ll r)
{
    __int128 ret = (r - l + 1) * b[x];
    __int128 res = (r - l + 1);
    res *= l + r;
    res /= 2;
    res *= c[x];
    if (c[x] == 0)
    {
        return ret;
    }
    if (c[x] > 0)
    {
        return ret + res;
    }
    ll im = (1 - b[x]) / c[x];
    if (im < l)
    {
        return r - l + 1;
    }
    if (im > r)
    {
        return ret + res;
    }
    ret = (im - l + 1) * b[x];
    res = (im - l + 1);
    res *= l + im;
    res /= 2;
    res *= c[x];
    res += r - im;
    return ret + res;
}
int fa[100005];
vector<int> g[100005];
void dfs(ll x, ll f)
{
    fa[x] = f;
    for (auto v : g[x])
    {
        if (v == f)
        {
            continue;
        }
        dfs(v, x);
    }
}
void write(__int128 x)
{
    if (x < 10)
    {
        ll t = x % 10;
        cout << t;
        return;
    }
    ll t = x % 10;
    write(x / 10);
    cout << t;
}
int n;
int t[100005], p[100005];
bool cmp(int x, int y)
{
    return t[x] < t[y];
}
int dis[100005];
inline bool chk(ll x)
{
    // cout << x << "\n";
    for (int i = 1; i <= n; i++)
    {
        if (sol(i, 1, x) < a[i])
        {
            return 0;
        }
        dis[i] = -1;
        p[i] = i;
        ll l = 1, r = n, rt = 0;
        while (l <= r)
        {
            ll mid = (l + r) >> 1;
            if (sol(i, mid, x) >= a[i])
            {
                rt = mid;
                l = mid + 1;
            }
            else
            {
                r = mid - 1;
            }
        }
        t[i] = rt;
        // cout << t[i] << " \n"[i == n];
    }
    // for (int i = 1; i <= n; i++)
    // {
    //     write(sol(i, t[i], x));
    //     cout << " \n"[i == n];
    // }
    sort(p + 1, p + n + 1, cmp);
    dis[0] = 0;
    ll ntm = 0;
    for (int i = 1; i <= n; i++)
    {
        ll nid = p[i];
        vector<int> v;
        while (dis[nid] == -1)
        {
            v.push_back(nid);
            nid = fa[nid];
        }
        reverse(v.begin(), v.end());
        for (auto j : v)
        {
            // cout << j << " " << ntm + 1 << "\n";
            dis[j] = ++ntm;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        // cout << dis[i] << " \n"[i == n];
        if (dis[i] > t[i])
        {
            return 0;
        }
    }
    return 1;
}
int main()
{
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i] >> b[i] >> c[i];
    }
    for (int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    int l = 0, r = 1e9;
    int ans = -1;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (chk(mid))
        {
            r = mid - 1;
            ans = mid;
        }
        else
        {
            l = mid + 1;
        }
    }
    cout << ans << "\n";
    return 0;
}

posted @ 2025-10-31 17:10  点燃genshin  阅读(0)  评论(0)    收藏  举报