Loading

Gold Transfer

算法

暴力算法还得排序

观察到重要信息

我们保证 \(c_i > c_{p_i}\) 成立

因此可以贪心, 从离根最近的点一路向北向下找到查询点

要快速找到最上方不为空的点, 联想到倍增法, 于是优化到 \(O(\log n)\)

总时间复杂度 \(O(n \log n)\)

代码

#include <bits/stdc++.h>
const int MAXN = 3e5 + 20;
#define int long long

struct node
{
    int Val;
    int Num;
} Tree[MAXN];
int fa[MAXN][30];

int q;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        x = x * 10 + ch - '0', ch = getchar();
    return x * f;
}

void Fa_init(int Start)
{
    for (int i = 1; i <= 20; i++)
    {
        if (~fa[Start][i - 1] && ~fa[fa[Start][i - 1]][i - 1])
            fa[Start][i] = fa[fa[Start][i - 1]][i - 1];
    }
}

int Min_Num, Min_Val;

void solve(int v, int w)
{
    while (w)
    {
        if (!Tree[v].Num)
            break;

        /*找 >0 的节点*/
        int Start = v;
        for (int i = 20; i >= 0; i--)
        {
            if (~fa[Start][i])
                if (Tree[fa[Start][i]].Num > 0)
                {
                    Start = fa[Start][i];
                }
        }

        /*计算(问题主要在找链上, 这里用循环方式解决)*/
        int Buy_Num = std::min(Tree[Start].Num, w);

        Min_Num += Buy_Num;
        Min_Val += Buy_Num * Tree[Start].Val;
        Tree[Start].Num -= Buy_Num;
        w -= Buy_Num;
    }
}

signed main()
{
    int Val_root, Num_root;
    q = read();
    Num_root = read();
    Val_root = read();
    Tree[0].Num = Num_root, Tree[0].Val = Val_root;

    for (int i = 0; i <= 20; i++)
    {
        fa[0][i] = -1;
    }

    for (int i = 1; i <= q; i++)
    {
        int op;
        int Fa_now, Val_now, Num_now;
        int v, w;

        op = read();
        if (op == 1)
        {
            Fa_now = read();
            Num_now = read();
            Val_now = read();
            fa[i][0] = Fa_now;
            Tree[i].Num = Num_now;
            Tree[i].Val = Val_now;
            Fa_init(i);
        }
        else
        {
            v = read();
            w = read();
            Min_Num = 0, Min_Val = 0;
            solve(v, w);

            printf("%lld %lld\n", Min_Num, Min_Val);
            fflush(stdout);
        }
    }

    return 0;
}

/*
5 5 2
2 0 2
1 0 3 4
2 2 4
1 0 1 3
2 4 2

2 4
4 10
1 3
*/

总结

观察题意优化代码

仔细读题

posted @ 2024-10-10 09:04  Yorg  阅读(20)  评论(0)    收藏  举报