51nod 1494 选举拉票【贪心】【扫描线】【线段树】

来源:互联网 发布:淘宝卖家联系客服电话 编辑:程序博客网 时间:2024/06/05 11:29

Description

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

题解

直接做很困难,所以我们想到了枚举我的选票数,所有选票数比我多的人的选票都要被我抢到小于我的选票数(一定是从小到大抢),这样抢来以后,不一定选票数达到了我枚举的选票数,所以我就需要从所有剩下的选票中选出一些来补上,这样就变成了求全局的前k小(可以直接用线段树),枚举的时候就是扫描线从大到小枚举,所有选票数比我多的人的选票中被我选出来的都要从线段树中删除。

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<queue>#define maxn 100006#define maxm 10006using namespace std;inline char nc(){    static char buf[100000],*i=buf,*j=buf;    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;}inline int _read(){    char ch=nc();int sum=0;    while(!(ch>='0'&&ch<='9'))ch=nc();    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();    return sum;}struct data{    int l,r,num,sum;}tree[maxm*4];int n,m,top,ans,a[maxn],stack[maxn];bool vis[maxn];priority_queue<int,vector<int> ,greater<int> > heap[maxn];void build(int p,int l,int r){    tree[p].l=l;tree[p].r=r;    if(l>=r)return;    int mid=(l+r)>>1;    build(p<<1,l,mid);build(p<<1|1,mid+1,r);}void update(int p,int t,int k){    if(tree[p].l>t||tree[p].r<t)return;    if(tree[p].l==tree[p].r){        tree[p].num+=k;tree[p].sum+=k*t;return;    }    update(p<<1,t,k);update(p<<1|1,t,k);    tree[p].num=tree[p<<1].num+tree[p<<1|1].num;    tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;}int query(int p,int k){    if(k<=0)return 0;    if(k>tree[p].num)return 2e9;    if(tree[p].l==tree[p].r)return tree[p].l*k;    if(k<=tree[p<<1].num)return query(p<<1,k);    return tree[p<<1].sum+query(p<<1|1,k-tree[p<<1].num);}bool cmp(int x,int y){return heap[x].size()>heap[y].size();}int main(){    freopen("nineteen.in","r",stdin);    freopen("nineteen.out","w",stdout);    n=_read();    build(1,0,10000);    memset(vis,1,sizeof(vis));    for(int i=1,x,y;i<=n;i++){        x=_read(),y=_read(),heap[x].push(y);        if(x&&vis[x])a[++m]=x,vis[x]=0;        if(x)update(1,y,1);    }    sort(a+1,a+1+m,cmp);    ans=2e9;int s=heap[0].size(),sum=0,num=0;    for(int i=n;i>=max(1,s);i--){        for(int j=1;j<=m;j++){            if(heap[a[j]].size()<i)break;            while(heap[a[j]].size()>=i)sum+=heap[a[j]].top(),update(1,heap[a[j]].top(),-1),heap[a[j]].pop(),num++;        }        ans=min(ans,sum+query(1,i-num-s));    }    printf("%d\n",ans);    return 0;}
原创粉丝点击