Codeforces 458C Elections 線段樹
阿新 • • 發佈:2018-11-10
使得0號的選票是最高的(不能有和0號相同)的最小花費
列舉0號的最終選票
那麼已知0號最終選票,則有些人選票比0號大的,那些票都要買下來。
如果買完了還是達不到 最終選票,就從所有剩下的選票裡找前k小的。
用線段樹求前k小的數的和
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define Max int(10000+10) #define INF 0x3f3f3f3f const int N=int (1e5+10); int n,cost,cnt; vector<int> g[N],a[N]; struct node { int r,l,size,sum; } tree[10004*4]; void build(int l,int r,int id) { tree[id].l=l; tree[id].r=r; tree[id].size=0; tree[id].sum=0; if(l==r) return ; int mid=(l+r)/2; build(l,mid,id*2); build(mid+1,r,id*2+1); } void update(int pos,int val ,int id) { if(tree[id].l==tree[id].r) { tree[id].size+=val; tree[id].sum+=pos*val; return ; } int mid=(tree[id].l+tree[id].r)/2; if(pos<=mid) update(pos,val,2*id); else update(pos,val,2*id+1); tree[id].size=tree[2*id].size+tree[2*id+1].size; tree[id].sum=tree[2*id].sum+tree[2*id+1].sum; } int query(int k,int id) { if(k<=0) return 0; if(tree[id].size<=k) return tree[id].sum; if(tree[id].l==tree[id].r) return min(k,tree[id].size)*tree[id].l; int mid=(tree[id].l+tree[id].r)/2; if(tree[2*id].size<=k) return tree[2*id].sum+query(k-tree[2*id].size,2*id+1); else return query(k,2*id); } int work(int h) { for(int i=0; i<a[h].size(); i++) { cost+=a[h][i]; update(a[h][i],-1,1); cnt++; } int need=h-cnt; if(need<=0) return cost; return cost+query(need,1); } int main() { while(~scanf("%d",&n)) { build(0,10004,1); int x,y; for(int i=0;i<N;i++) a[i].clear(),g[i].clear(); for(int i=0; i<n; i++) { scanf("%d%d",&x,&y); g[x].push_back(y); update(y,1,1); } for(int i=1; i<N; i++) sort(g[i].begin(),g[i].end()); for(int i=0; i<N; i++) for(int j=0; j<g[i].size(); j++) a[g[i].size()-j].push_back(g[i][j]); cost=0; cnt=0; int sum=1e9+10; for(int i=n; i>=0; i--) { int ans=work(i); if(ans==-1) break; sum=min(sum,ans); } printf("%d\n",sum); } return 0; } /* 5 1 2 1 2 1 2 2 1 0 0 3 */