CF 458C - Elections (枚举 + 线段树)
2014-08-11 14:39
369 查看
题意:有n个人,每个人都有一个选票,第i个人想要选编号为ai的人,如果想贿赂这个人让他选自己,就需要花费bi,问想让自己获胜(得票最多)的最小花费是多少。
思路:枚举一下最终的得票数,那么对于比当前枚举的票数多的人,那么多出的那部分一定要买走,剩下的,就是在剩下的人中,选择花费最少的人让自己得到相应的票数。从大到小枚举票数,假设之前枚举到k,那么枚举k-1时,在k要收买多出的那部分在k-1的时候也要收买,因此,这部分人会不断减少。将花费从小到大排序以后,插入线段树,线段树维护区间和还有区间中还没被收买的人的数量。那么,如果枚举到k,此时一定要收买的人有p个,那么就要在线段树中找前k-p个人就好了。
代码:
思路:枚举一下最终的得票数,那么对于比当前枚举的票数多的人,那么多出的那部分一定要买走,剩下的,就是在剩下的人中,选择花费最少的人让自己得到相应的票数。从大到小枚举票数,假设之前枚举到k,那么枚举k-1时,在k要收买多出的那部分在k-1的时候也要收买,因此,这部分人会不断减少。将花费从小到大排序以后,插入线段树,线段树维护区间和还有区间中还没被收买的人的数量。那么,如果枚举到k,此时一定要收买的人有p个,那么就要在线段树中找前k-p个人就好了。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<set> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-8 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn=100000+10; struct Node { int id,a,b; Node(int id=0,int a=0,int b=0):id(id),a(a),b(b){} bool operator < (const Node &a) const { return b < a.b; } }node[maxn]; vector<Node>vt[maxn]; int rank[maxn],used[maxn]; bool cmp(int a,int b) { return vt[a].size() > vt[b].size(); } int cnt[maxn<<2],sum[maxn<<2]; void PushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; cnt[rt] = cnt[rt<<1] + cnt[rt<<1|1]; } void build(int l,int r,int rt) { if(l == r) { cnt[rt] = 1; sum[rt] = node[l].b; return ; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); PushUp(rt); } void Update(int p,int l,int r,int rt) { if(l == r) { cnt[rt] = sum[rt] =0; return ; } int m =(l+r)>>1; if(m >= p) Update(p,l,m,rt<<1); else Update(p,m+1,r,rt<<1|1); PushUp(rt); } int Query(int k,int l,int r,int rt) { if(l == r) return sum[rt]; int m=(l+r)>>1; if(cnt[rt<<1] >= k) return Query(k,l,m,rt<<1); else return sum[rt<<1] + Query(k-cnt[rt<<1],m+1,r,rt<<1|1); } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w ",stdout); int n; scanf("%d",&n); for(int i =1 ;i <= n;++i) scanf("%d%d",&node[i].a,&node[i].b); sort(node + 1,node + n +1); for(int i =1 ;i <= n;++i) node[i].id = i; for(int i =1;i <= n;++i) { vt[node[i].a].push_back(node[i]); } for(int i = 0;i < maxn ;++i) rank[i] = i; sort(rank,rank + maxn -1,cmp); build(1,n,1); int ans = inf,last = 0,has = 0,tmp; Node nd; for(int i = n;i >= 1;--i) { for(int j = 0;j < maxn;++j) { int x = rank[j]; if((int)vt[x].size() - used[x] >= i) { nd = vt[x][used[x]]; last += nd.b; Update(nd.id,1,n,1); used[x]++; has++; } else break; } tmp = last; if(has < i) { tmp += Query(i-has,1,n,1); } ans = min(ans,tmp); } printf("%d\n",ans); return 0; }
相关文章推荐
- 【扫描线+贪心+线段树】Codeforces 458C Elections
- CF-30 D - King's Problem?(枚举+最短路)
- CF 112D. Petya and Divisors 枚举(标记倍数最后出现位置)
- CF 558E 线段树
- [莫队算法 线段树 斐波那契 暴力] CF 633H Fibonacci-ish II
- CF 242E(div 2) n课线段树更新
- CF 242E(zkw线段树-拆位)
- CF 243D Cubes(线段树)
- CF-30 D - King's Problem?(枚举+最短路)
- CF 876F High City 单调栈,枚举,或运算
- CF 213E Two Permutations(线段树,hash)
- CF 452F Permution 神奇的线段树判断
- CF 46 D. Parking Lot(线段树)
- CF 258E Little Elephant and Tree 【线段树,树上DFS序列】
- CF 19D, 线段树套set/KD-tree
- (CF)B. Restore Cube (暴力枚举判断)
- CF 558E A Simple Task (线段树)
- CF 558E 线段树
- CF 787D 线段树套堆优化Dij
- CF-63C - Bulls and Cows(枚举)