[枚举 线段树] 51Nod1494 选举拉票

来源:互联网 发布:全职高手之烽火知韩 编辑:程序博客网 时间:2024/05/22 15:25

直接做不太可做,我们可以枚举一个 d 表示其他人最大值不大于 d 时的情况。 这样就好做多了,比 d 大的部分就一定要全部扣掉。然后如果自己的票数不足 d ,就需要在剩下的所有票里取最便宜的前几个,需要线段树询问前k小值的加和。
从大到小枚举 d 即可。

#include<cstdio>#include<vector>#include<algorithm>#define Fir first#define Sec second#define mp(x,y) make_pair(x,y)using namespace std;const int maxn=100005; vector<int> a[maxn];pair<int,int> b[maxn];int n,m,all;bool _cmp(const int &x,const int &y){ return x>y; }int res,ans;struct node{    int cnt,sum; node* ch[2];    node(){ cnt=sum=0; ch[0]=ch[1]=0; }    void maintain(){        cnt=ch[0]->cnt+ch[1]->cnt;        sum=ch[0]->sum+ch[1]->sum;    }} *root;typedef node* P_node;P_node Build(int L,int R){    P_node p=new node();    if(L==R) return p;    int mid=(L+R)>>1;    p->ch[0]=Build(L,mid); p->ch[1]=Build(mid+1,R);    return p;}void Updata(P_node p,int L,int R,int pos,int k){    if(R<pos||pos<L) return;    if(L==R){ p->cnt+=k; p->sum+=L*k; return; }    int mid=(L+R)>>1;    Updata(p->ch[0],L,mid,pos,k); Updata(p->ch[1],mid+1,R,pos,k);    p->maintain();}int Query(P_node p,int L,int R,int k){    if(L==R) return L*k;    int mid=(L+R)>>1;    if(p->ch[0]->cnt>=k) return Query(p->ch[0],L,mid,k);    return p->ch[0]->sum+Query(p->ch[1],mid+1,R,k-p->ch[0]->cnt);}int main(){    freopen("51nod1494.in","r",stdin);    freopen("51nod1494.out","w",stdout);    scanf("%d",&n);    for(int i=1;i<=n;i++){        int x,y; scanf("%d%d",&x,&y);        a[x].push_back(y);    }    root=Build(0,10000);    all=a[0].size();    for(int i=1;i<=100000;i++){        sort(a[i].begin(),a[i].end(),_cmp);        for(int j : a[i]) Updata(root,0,10000,j,1);        b[++m]=mp(-a[i].size(),i);    }    sort(b+1,b+1+m);    ans=2e9;    for(int d=n;d>=0;d--){        for(int i=1;i<=m;i++){            if(a[b[i].Sec].size()<=d) break;            while(a[b[i].Sec].size()>d){                int t=*a[b[i].Sec].rbegin(); a[b[i].Sec].pop_back();                res+=t; all++; Updata(root,0,10000,t,-1);            }        }        if(all>d){ ans=min(ans,res); break; }        if(d+1-all<=root->cnt) ans=min(ans,res+Query(root,0,10000,d+1-all));    }    printf("%lld\n",ans);    return 0;} 
原创粉丝点击