CF 457C Elections 解题报告(线段树)

C. Elections
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are running for a governor in a small city in Russia. You ran some polls and did some research, and for every person in the city you know whom he will vote for, and how much it will cost to bribe that person to vote for you instead of whomever he wants to vote for right now. You are curious, what is the smallest amount of money you need to spend on bribing to win the elections. To win elections you need to have strictly more votes than any other candidate.

Input

First line contains one integer n (1 ≤ n ≤ 105) — number of voters in the city. Each of the next n lines describes one voter and contains two integers ai and bi (0 ≤ ai ≤ 105; 0 ≤ bi ≤ 104) — number of the candidate that voter is going to vote for and amount of money you need to pay him to change his mind. You are the candidate 0 (so if a voter wants to vote for you, ai is equal to zero, in which case bi will also be equal to zero).

Output

Print one integer — smallest amount of money you need to spend to win the elections.

Sample test(s)
input
5
1 2
1 2
1 2
2 1
0 0
output
3
input
4
1 2
1 2
2 1
0 0
output
2
input
1
100000 0
output
0

    解题报告: 昨晚(准确来说是今天早上)CF上的比赛第三题。前两题1小时多搞定了,这题一直没有想法。比赛后就去睡了。白天看了前几名的代码,然后就有点头绪了。

    我们的目标是用最少的钱使自己的票数多余其他人的票数。我们可以直接买票比我们当前票数多的那些人的票,这样我们的票增加了,他们的票减少了;我们也可以直接买最便宜的票,直到超过所有其他人。这样我们可以枚举最后其他人的票最多有多少。减少的票我们都买下来,不够我们就继续买最便宜的。最终取结果的最小值。

    代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define fit(it, n) for(auto it = (n).begin(); it != (n).end(); it++)
#define bit(n) (1LL<<(n))
typedef long long LL;
typedef unsigned long long ULL;
void work();
int main()
{
#ifdef ACM
    freopen("in.txt", "r", stdin);
#endif // ACM
    work();
}

/***************************************************/

#define lson l, m, pos<<1
#define rson m+1, r, pos<<1|1
const int maxn = 111111;
int num[maxn<<2];
int pri[maxn<<2];

int p[maxn], si[maxn];

bool cmp(int a, int b)
{
    return si[a] > si[b];
}

void updateFather(int pos)
{
    num[pos] = num[pos<<1] + num[pos<<1|1];
    pri[pos] = pri[pos<<1] + pri[pos<<1|1];
}

void update(int p, int x, int l = 0, int r = 10000, int pos = 1)
{
    if (l == r)
    {
        num[pos] += x;
        pri[pos] += x * p;

        return;
    }

    int m = (l+r)/2;
    if (p <= m)
        update(p, x, lson);
    else
        update(p, x, rson);

    updateFather(pos);
}

int query(int k, int l = 0, int r = 10000, int pos = 1)
{
    if (k == 0) return 0;
    if (l == r) return pri[pos]/num[pos]*k;
    if (k == num[pos]) return pri[pos];

    int m = (l+r)/2;
    if (k <= num[pos<<1])
        return query(k, lson);
    else
        return pri[pos<<1] + query(k-num[pos<<1], rson);
}

void work()
{
    int n;
    while (scanf("%d", &n) == 1)
    {
        memset(num, 0, sizeof(num));
        memset(pri, 0, sizeof(pri));

        map> vote;
        ff (i, n)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            if(a) vote[a].insert(b);
            update(b, 1);
        }

        int L = 0;
        fit (it, vote)
        {
            p[L++] = it->first;
            si[it->first] = it->second.size();
        }
        sort(p, p+L, cmp);

        int ans = 2e9;
        int vnum = 0, vsum = 0;
        int end = 0;
        dff(i, n, 1)
        {
            while(end < L && si[p[end]] >= i) end ++;
            ff(j, end)
            {
                auto it = vote[p[j]].begin();
                int price = *it;
                vnum ++;
                vsum += price;
                update(price, -1);
                vote[p[j]].erase(it);
            }
            ans = min(ans, vsum + query(max(i-vnum, 0)));
        }

        printf("%d\n", ans);
    }
}


你可能感兴趣的:(ACM,线段树,思维)