zoukankan      html  css  js  c++  java
  • 51Nod-1494 选举拉票 权值线段树

    51Nod-1494 选举拉票 权值线段树

    题意

    现要竞选市长。有(n)个选民投票。

    每行两个数字(a_i,b_i)表示第(i)个选民投给(a_i)号候选人,必须花费(b_i)使他投你的票。

    你是第0号候选人。

    问最少花多少钱使你竞选成功。

    [1leq n leq 10^5\ 0leq a_i leq 10^5,0leq b_i leq 10^4 ]

    分析

    (n - st到max(1,st))枚举要收买多少人。

    假设对每个候选人票数小于(i)要收买(num)个人。那么还需要(i - num)个人。

    显然我们贪心的选择剩下的人。

    为了快速计算这些人的总和,可以建立一颗权值线段树,做到单次查询(O(logn))

    权值线段树的节点下标(不是真正的下标)表示权值,num表示个数,sum表示总和(方便询问)

    还要注意这里如果size小于i就直接break,大大减少了循环次数。这也是之前排序的原因。

    代码

    priority_queue<int, vector<int>, greater<int> > q[maxn];
    vector<int> id;
    int vis[maxn];
    int cnt;
    int st;
    
    bool cmp(int x, int y) {
        return q[x].size() > q[y].size();
    }
    
    struct Node {
        int num, sum;
    };
    
    Node node[maxn << 2];
    
    void push_up(int i) {
        node[i].num = node[i << 1].num + node[i << 1 | 1].num;
        node[i].sum = node[i << 1].sum + node[i << 1 | 1].sum;
    }
    
    void update(int i, int l,int r,int p, ll v) {
        if (l == r) {
            node[i].num += v;
            node[i].sum += l * v;
            return;
        }
        int mid = l + r >> 1;
        if (p <= mid) update(i << 1, l, mid, p, v);
        else update(i << 1 | 1, mid + 1, r, p, v);
        push_up(i);
    }
    
    int query(int i, int l, int r, int k) {
        if (k <= 0) return 0;
        if (node[1].num <  k) return 2e9;
        if (l == r) return l * k;
        int mid = l + r >> 1;
        if (k <= node[i << 1].num) return query(i << 1, l, mid, k);
        else return node[i << 1].sum + query(i << 1 | 1, mid + 1, r, k - node[i << 1].num);
    }
    
    
    
    int main() {
        int n = readint();
        for (re int i = 0; i < n; i++) {
            int x, y;
            x = readint();
            y = readint();
            if (!x) {
                st++;
                continue;
            }
            q[x].push(y);
            update(1, 0, 10000, y, 1);
            if (!vis[x]) {
                vis[x] = 1;
                id.push_back(x);
            }
        }
        sort(id.begin(), id.end(),cmp);
        int ans = INF;
        int res = 0, num = 0;
        int mx = max(1, st);
        for (re int i = n; i >= mx; i--) {
            for (re int j = 0; j < id.size(); j++) {
                int xx = id[j];
                if (q[xx].size() < i) break;
                while (q[xx].size() >= i) {
                    int yy = q[xx].top();
                    res += yy;
                    update(1, 0, 10000,yy, -1);
                    q[xx].pop();
                    num++;
                }
            }
            ans = min(ans, res + query(1, 0, 10000, i - num - st));
        }
        Put(ans);
    }
    
  • 相关阅读:
    占德国与哥斯达黎加
    晕,终于见识到了J2me的代码容量限制
    使用Adobe Acrobat SDK 需注意的要点
    看到一窝火的对联
    Entity Framework 学习初级篇4Entity SQL(转)
    Entity Framework 学习初级篇6EntityClient(转)
    ASP.NET MVC3 快速入门第三节 添加一个视图(转)
    ASP.NET MVC3 快速入门第一节 概述(转)
    Entity Framework 学习初级篇1EF基本概况(转)
    PB TreeView 查找节点(转)
  • 原文地址:https://www.cnblogs.com/hznumqf/p/13773421.html
Copyright © 2011-2022 走看看