• Codeforces1099F. Cookies(线段树+dp+贪心+博弈)


    题目链接:传送门

    思路:

      分析到处理节点时的吃cookie的顺序了,然鹅不会用线段树维护前缀和。技术门槛QAQ。。。

      很容易想到可以从root开始搜索,每次深入消耗时间2*边权w。

      然后对于深入到点u开始返回的话,想要尽量多地吃cookie,就要贪心地选择用时短的cookie,也就是:

        当前节点为u,剩余时间为val时,最多能在1-u这条链上吃到多少个cookie。

      一共有1e6个节点,所以这个贪心策略的实现复杂度要压到log级别。。。好难不会。


    思路参考:Dream_maker_yk的博客

      线段树维护前缀和。

      首先我们以时间ti为坐标向线段树中插入节点。保存两个值,把子树吃光所用的总时间sum,子树中的cookie总数cnt。

      然后根据剩余时间val查询,如果左子树的sum比val小,那么说明左子树可以吃光,那么查询结果就是:

        cnt左子树 + 对右子树查询val - sum左子树

      这样我们就可以用logn的时间实现贪心策略了。


      然后考虑到Vasya会干扰我们,所以应题目要求,我们要求在Vasya干扰得最好的情况下,能吃到的最大的cookie数量。

      最差的情况就是Vasya每次深入后都把最好的子树f1给办掉了,那么我们只能选次好的子树f2。

      因为每个节点都可能返回,所以回溯当前节点的最多cookie数ans。而当前节点的最多cookie数可能是吃到当前节点为止,也可能是吃到当前节点的子树,所以ans = max(ans,f2)。

      特别地,因为Mitya是先手,所以root的子树不会被办,ans = max(ans,f1)。

    代码:

    #include <bits/stdc++.h>
    #define lson (pos << 1)
    #define rson (pos << 1 | 1)
    
    using namespace std;
    typedef long long ll;
    const int MAX_N = 1e6 + 5;
    
    struct Edge{
        int v;
        ll w;
    };
    ll x[MAX_N], t[MAX_N];
    vector <Edge> g[MAX_N];
    
    ll sum[MAX_N<<2], cnt[MAX_N<<2];
    
    void update(int pos, int l, int r, ll xi, ll ti) {
        sum[pos] += xi*ti;
        cnt[pos] += xi;
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        if (ti <= mid)
            update(lson, l, mid, xi, ti);
        else
            update(rson, mid+1, r, xi, ti);
    }
    
    ll query(int pos, int l, int r, ll val) {
        if (l == r)
            return min(cnt[pos], val/l);
        int mid = (l + r) >> 1;
        if (sum[lson] <= val)
            return cnt[lson] + query(rson, mid+1, r, val - sum[lson]);
        else
            return query(lson, l, mid, val);
    }
    
    ll dfs(int u, ll res) {
        update(1, 1, 1e6, x[u], t[u]);
        ll ans = query(1, 1, 1e6, res);
        ll f1 = 0, f2 = 0;
        for (const auto &tmp : g[u]) {
            int v = tmp.v;
            ll w = tmp.w;
            if (res < 2*w)
                continue;
            ll f = dfs(v, res - 2*w);
            if (f > f1)
                f2 = f1, f1 = f;
            else if (f > f2)
                f2 = f;
        }
        update(1, 1, 1e6, -x[u], t[u]);
        if (u == 1)
            return max(ans, f1);
        else
            return max(ans, f2);
    }
    
    int main()
    {
        std::ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        ll T;
        cin >> n >> T;
        for (int i = 1; i <= n; i++)
            cin >> x[i];
        for (int i = 1; i <= n; i++)
            cin >> t[i];
        for (int u = 2; u <= n; u++) {
            int v;
            ll w;
            cin >> v >> w;
            g[v].push_back((Edge){u, w});
        }
    
        ll ans = dfs(1, T);
    
        cout << ans << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    自定义控制器的View(loadView)及其注意点
    多控制器之UIWindow
    多控制器之UIApplication
    浅谈Xcode5和Xcode7在系统创建的文件夹和文件中的区别
    自动计算label字体的高度和图片拉伸处理(封装成分类分享)
    左滑功能和多选功能(在一些列表都会用到的功能)
    数据刷新
    字典转模型第三方框架---MJExtension
    UI之UItableView重用机制的性能问题
    如何设置苹果电脑自带的wife连接手机
  • 原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/10242048.html
Copyright © 2020-2023  润新知