Codeforces 458C Elections 贿赂选票抢主席! 线段树

题目链接:点击打开链接

题意:

给定n张选票,每张选票有2个参数,第一个参数表示这张选票选的人

第二个参数表示如果让这张选票改为选0号 的花费


问:使得0号的选票是最高的(不能有和0号相同)的最小花费

枚举0号的最终选票

那么已知0号最终选票,则有些人选票比0号大的,那些票都要买下来。

如果买完了还是达不到 最终选票,就从所有剩下的选票里找前k小的。

用线段树求前k小的数的和,然后_(:зゝ∠)_就可以了


#include
#include
#include
#include
#include
#include
using namespace std;
#define N 100005
#define inf 100000000
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define Sum(x) tree[x].sum
#define Siz(x) tree[x].siz
#define Lson(x) tree[x].l
#define Rson(x) tree[x].r
inline int Mid(int x, int y){return (x+y)>>1;}
struct node{
    int l, r, siz, sum;
}tree[10004*4];
void push_up(int id){
    Sum(id) = Sum(L(id)) + Sum(R(id));
    Siz(id) = Siz(L(id)) + Siz(R(id));
}
void build(int l, int r, int id){
    Lson(id) = l, Rson(id) = r;
    Sum(id) = Siz(id) = 0;
    if(l==r) return ;
    int mid = Mid(l,r);
    build(l, mid, L(id));
    build(mid+1, r, R(id));
}
void updata(int pos, int val, int id){
    if(Lson(id) == Rson(id))
    {
        Siz(id) += val;
        Sum(id) += pos*val;
        return ;
    }
    int mid = Mid(Lson(id), Rson(id));
    if(pos <= mid)
        updata(pos, val, L(id));
    else
        updata(pos, val, R(id));
    push_up(id);
}
int query(int k, int id){
	if(k<=0)return 0;
	if(Siz(id) <= k)
    {
        return Sum(id);
    }
	if(Lson(id) == Rson(id)){
		return min(Siz(id), k) * Lson(id);
	}
    int mid = Mid(Lson(id), Rson(id));
    if(Siz(L(id)) <= k)
    {
        return Sum(L(id)) + query(k - Siz(L(id)), R(id));
    }
    else query(k, L(id));
}
vector a[N], G[N];
int n, cost, now;
int work(int x){
    for(int i = 0; i < G[x].size(); i++)
    {
        cost += G[x][i];
        updata(G[x][i], -1, 1);
        now ++;
    }
    int hehe = x - now;
    if(hehe<=0)return cost;
    return cost+query(hehe, 1);
}
void input(){
    build(0, 10004, 1);
    for(int i = 0; i < N; i++)a[i].clear(), G[i].clear();
    for(int i = 1; i <= n; i++)
    {
		int u, v;
        scanf("%d %d",&u,&v);
        a[u].push_back(v);
        updata(v, 1, 1);
    }
    for(int i = 1; i < N; i++)sort(a[i].begin(), a[i].end());
    for(int i = 0; i < N; i++)
    {
        for(int j = 0; j < a[i].size(); j++)
        {
            G[a[i].size() - j].push_back(a[i][j]);
        }
    }
}
int main(){
    int i, j, u, v;
    while(~scanf("%d",&n))
    {
        input();
        int ans = 1e9+10;
        cost = 0;
        now = 0;
        for(i = n; i >= 0; i--)
        {
            int tmp = work(i);
            if(tmp == -1)break;
            ans = min(ans, tmp);
        }
        cout<


你可能感兴趣的:(线段树,codeforce)