51nod 1494 选举拉票&&cf458C

来源:互联网 发布:晋江网络 编辑:程序博客网 时间:2024/05/21 09:49

中文题面
考虑把所有人的票分别从大到小排序之后可以看做n条线段
枚举自己的票数为i,所以每条线段超过i的部分必须收买,如果还不够就到前面挑不够的

0b[i]104求前k小想到权值线段树(应该是类似的东西)

#include<cstdio>#include<algorithm>#include<vector>#define N 100000#define LL long longusing namespace std;inline char nc() {    static char buf[100000],*p1=buf,*p2=buf;    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void read(int &x) {    char c=nc(),b=1;    for(;!(c>='0'&&c<='9');c=nc()) if(c=='-') b=-1;    for(x=0;c>='0'&&c<='9';x=x*10+c-'0',c=nc()); x*=b;}vector<int>a[N+5],f[N+5];int n,m,num[N*4];LL sum,ans,t[N*4];void change(int x,int l,int r,int q) {    if(l==r) {        ++num[x];        t[x]+=1ll*l;        return;    }    int mid=(l+r)>>1;    if(q<=mid) change(x<<1,l,mid,q);    else change(x<<1|1,mid+1,r,q);    t[x]=t[x<<1]+t[x<<1|1];    num[x]=num[x<<1]+num[x<<1|1];}LL query(int x,int l,int r,int q) {    if(l==r) return 1ll*l*q;    int mid=(l+r)>>1;    if(q==num[x<<1]) return t[x<<1];    if(q>num[x<<1]) return t[x<<1]+query(x<<1|1,mid+1,r,q-num[x<<1]);    else return query(x<<1,l,mid,q);}bool cmp(int x,int y) {return x>y;}int main() {    read(n);    int maxn=1,peo=0;    ans=0;    for(int i=1,x,y;i<=n;++i) {        read(x),read(y);        peo=max(peo,x);        if(y==0) continue;        maxn=max(y,maxn);        ans+=1ll*y;        a[x].push_back(y);    }    for(int i=1;i<=peo;++i)        if(a[i].size()) {            sort(a[i].begin(),a[i].end(),cmp);            for(int j=0;j<a[i].size();++j)                f[j+1].push_back(a[i][j]);        }    int k=n;    LL tmp=ans;    for(int i=1;i<=n;++i) {        k-=f[i].size();        for(int j=0;j<f[i].size();++j)            change(1,1,maxn,f[i][j]),tmp-=1ll*f[i][j];        LL add=0;        if(k<=i)            add=query(1,1,maxn,min(i+1-k,n));        ans=min(ans,tmp+add);    }    printf("%lld\n",ans);    return 0;}
原创粉丝点击