• 51nod 1494 选举拉票 (线段树+扫描线)


    题目来源: CodeForces
    基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
     收藏
     关注

    现在你要竞选一个县的县长。你去对每一个选民进行了调查。你已经知道每一个人要选的人是谁,以及要花多少钱才能让这个人选你。现在你想要花最少的钱使得你当上县长。你当选的条件是你的票数比任何一个其它候选人的多(严格的多,不能和他们中最多的相等)。请计算一下最少要花多少钱。

    Input
    单组测试数据。
    第一行有一个整数n (1 ≤ n ≤ 10^5),表示这个县的选民数目。
    接下来有n行,每一行有两个整数ai 和 bi (0 ≤ ai ≤ 10^5; 0 ≤ bi ≤ 10^4),表示第i个选民选的是第ai号候选人,想要让他选择自己就要花bi的钱。你是0号候选人(所以,如果一个选民选你的话ai就是0,这个时候bi也肯定是0)。
    Output
    输出一个整数表示花费的最少的钱。
    Input示例
    5
    1 2
    1 2
    1 2
    2 1
    0 0
    Output示例
    3

    思路:
    线段树+扫描线思想
    实现代码:
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    const ll M = 1e5 + 10;
    vector<ll>g[M];
    vector<ll>rk[M];
    ll sum[M<<2],num[M<<2];
    void pushup(ll rt){
        num[rt] = num[rt<<1] + num[rt<<1|1];
        sum[rt] = sum[rt<<1|1] + sum[rt<<1];
    }
    
    void update(ll p,ll l,ll r,ll rt){
        if(l == r){
            sum[rt] += l;
            num[rt] ++;
            return ;
        }
        ll m = (l + r) >> 1;
        if(p <= m) update(p,lson);
        else update(p,rson);
        pushup(rt);
    }
    
    ll query(ll p,ll l,ll r,ll rt){
        if(l == r)
            return l*p;
        ll m = (l + r) >> 1;
        if(p == num[rt<<1]) return sum[rt<<1];
        else if(p < num[rt<<1])  return query(p,lson);
        else return sum[rt<<1] + query(p - num[rt<<1],rson);
    }
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        ll n,u,v;
        ll mx = 0,ans = 0;
        cin>>n;
        for(ll i = 1;i <= n;i ++){
            cin>>u>>v;
            if(v == 0) continue;
            ans += v;
            mx = max(mx,v);
            g[u].push_back(v);
        }
        for(ll i = 1;i <= M;i ++){
            if(g[i].size()){
                sort(g[i].begin(),g[i].end(),greater<ll>());
                for(ll j = 0;j < g[i].size();j ++){
                    rk[j].push_back(g[i][j]);
                }
            }
        }
        ll nn = n;
        ll minn = ans,cnt = 0;
        for(ll i = 0;i < n;i ++){
            nn -= rk[i].size();
            if(rk[i].size()==0) continue;
            for(ll j = 0;j < rk[i].size();j ++){
                ans -= rk[i][j];
                update(rk[i][j],1,mx,1);
            }
            if(nn <= i+1){
                 cnt = query(min(n,i+2-nn),1,mx,1);
            }
            minn = min(minn,ans+cnt);
        }
        cout<<minn<<endl;
    }
  • 相关阅读:
    Linux命令 tr
    Linux命令 xargs
    Python 文件读写 文件和路径
    Python 正则表达式 匹配任意字符
    Python 正则表达式 贪心匹配和非贪心匹配
    Python 正则表达式 匹配次数
    Python 正则表达式 利用括号分组
    Python 正则表达式 search vs match
    【转-整理】 SQL2008 提示评估期已过的解决方法
    Java http接口进阶——自我理解为接口框架形式
  • 原文地址:https://www.cnblogs.com/kls123/p/9038400.html
Copyright © 2020-2023  润新知