zoukankan      html  css  js  c++  java
  • Luogu P1552 [APIO2012]派遣 主席树

    题目链接 Click Here

    这个题好像大多数人用的都是左偏树啊?这里我来贡献一发主席树的解法。

    把题目中的问题抽象出来,其实就是询问每一个点的子树中,工资前(tot_i)大的点,使它们的和满足(sum cost_i<=m),在此前提下使(tot_i)尽可能大,答案就是(ans=max(tot_i*lead_i))

    如果只有一个点的话直接二分一下就好了,但现在树上的每一个点都可能是答案的产生1处。为了便于访问每一棵子树,我们把原先的树按(dfs)序划分,子树显然就是连续的一个序列。紧接着我们按(dfs)序对整棵树进行维护,最后在主席树上每个点二分一下(tot_i)的大小就好啦~

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    const int N = 100010;
    int ans;
    int n, m, rt, cnt, sz[N], dfn[N], cost[N], lead[N], head[N];
    
    struct edge {
        int nxt, to;
    
        edge (int _nxt = 0, int _to = 0) {
            nxt = _nxt, to = _to;
        }
    }e[N << 1];
    
    void add_len (int u, int v) {
        e[++cnt] = edge (head[u], v); head[u] = cnt;
        e[++cnt] = edge (head[v], u); head[v] = cnt;
    }
    
    #define mid ((l + r) >> 1)
    
    int tot;
    
    struct Segment_Tree {
        struct Segment_Node {
            int ls, rs, sz, sum;
            Segment_Node () {sum = ls = rs = sz = 0;}
        }t[N << 5];
        
        int modify (int _rt, int l, int r, int w) {
            int p = ++tot;
            t[p].ls = t[_rt].ls;
            t[p].rs = t[_rt].rs;
            t[p].sz = t[_rt].sz + 1;
            t[p].sum = t[_rt].sum + w;
            if (l != r) {
                if (w <= mid) {
                    t[p].ls = modify (t[_rt].ls, l, mid, w);
                } else {
                    t[p].rs = modify (t[_rt].rs, mid + 1, r, w);
                }
            }
            return p;
        }
    
        #undef mid
    
        int query (int u, int v, int l, int r, int m) {
            int ans = 0;
            while (l < r) {
                int mid = (l + r) >> 1;
                int suml = t[t[v].ls].sum - t[t[u].ls].sum;
                // printf ("v = %d, t[v].sum = %d, t[v].sz = %d, t[ls].sum = %d, t[ls].sz = %d
    ", v, t[v].sum, t[v].sz, t[t[v].ls].sum, t[t[v].ls].sz);
                // printf ("l = %d, r = %d, m = %d, mid = %d, suml = %d, sz = %d
    ", l, r, m, mid, suml, t[t[v].ls].sz - t[t[u].ls].sz);
                if (m <= suml) {
                    u = t[u].ls;
                    v = t[v].ls;
                    r = mid;
                } else {
                    ans += t[t[v].ls].sz - t[t[u].ls].sz;
                    u = t[u].rs;
                    v = t[v].rs;
                    l = mid + 1;
                    m -= suml;
                }
            }
            // printf ("m = %d, r = %d, ans = %d
    ", m, r, ans);
            ans += floor ((1.0 * m) / (1.0 * r));
            // printf ("ans = %d
    ", ans);
            return ans;
        }
    }tree;
    
    int root[N];
    void pre (int u, int fa) {
        sz[u] = 1;
        dfn[u] = ++dfn[0];
        root[dfn[u]] = tree.modify (root[dfn[u] - 1], 1, m, cost[u]);
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].to;
            if (v != fa) {
                pre (v, u);
                sz[u] += sz[v];
            }
        }
    }
    
    signed main () {
        cin >> n >> m;
        for (int u = 1; u <= n; ++u) {
            static int v;
            cin >> v >> cost[u] >> lead[u];
            if (v == 0) {
                rt = u;
            } else {
                add_len (u, v);
            }
        }
        pre (rt, 0);
        for (int u = 1; u <= n; ++u) {
            int dfnu = dfn[u];
            int dfnv = dfn[u] + sz[u] - 1;
            ans = max (ans, 1LL * lead[u] * tree.query (root[dfnu - 1], root[dfnv], 1, m, m));
        }
        cout << ans << endl;
    } 
    
    
  • 相关阅读:
    Google Accounts,OpenID,OAuth
    Namespaces(命名空间)
    <Araxis Merge>Windows平台下的Merge概览
    <Araxis Merge>快速一览文件的比较与合并
    <Araxis Merge>保存文件
    <Stackoverflow> 声望和节制
    <Stackoverflow> 如何提问
    收集一些好用的搜索引擎
    一个简单的scrapy爬虫抓取豆瓣刘亦菲的图片地址
    应用python编写简单新浪微博应用(一)
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10523010.html
Copyright © 2011-2022 走看看