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;
}

猜你喜欢

转载自www.cnblogs.com/kls123/p/9038400.html