51Nod 1494 选举拉票(权值线段树)

Posted ccsu-kid

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51Nod 1494 选举拉票(权值线段树)相关的知识,希望对你有一定的参考价值。

http://www.51nod.com/Challenge/Problem.html#!#problemId=1494

题解

一开始有start个人投自己,num表示当前已经收买了多少人,从大到小枚举自己以i张票当选,那么其他人的票数一定要小于i,拿钱收买他们花费最少的>=i的这部分人,再加上另外要收买的i-start-num个最便宜收买的花费就是当前答案,这里可以对每个人的收买代价建立权值线段树来查找收买前i-start-num个最便宜的花费。注意不是选自己的选民可以选别人的时候叛变花费可能为0,所以线段树应该从0开始。

 1 #define dbg(x) cout<<#x<<" = "<< (x)<< endl
 2 #define IO std::ios::sync_with_stdio(0);
 3 #include <bits/stdc++.h>
 4 #define iter ::iterator
 5 using namespace  std;
 6 typedef long long ll;
 7 typedef pair<ll,ll>P;
 8 #define pb push_back
 9 #define se second
10 #define fi first
11 #define rs o<<1|1
12 #define ls o<<1
13 const ll inf=0x7fffffff;
14 const int N=1e5+10;
15 int M;
16 priority_queue<ll,vector<ll>,greater<ll> >q[N];
17 int id[N],vis[N],cnt;
18 ll start;
19 bool cmp(ll x,ll y){
20     return q[x].size()>q[y].size();
21 }
22 struct node{
23     ll num,sum;
24 }a[N*4];
25 void push(int o){
26     a[o].num=a[ls].num+a[rs].num;
27     a[o].sum=a[ls].sum+a[rs].sum;
28 }
29 void up(int o,int l,int r,int p,ll v){
30     if(l==r){
31         a[o].num+=v;
32         a[o].sum+=v*l;
33         return;
34     }
35     int m=(l+r)/2;
36     if(p<=m)up(ls,l,m,p,v);
37     else up(rs,m+1,r,p,v);
38     push(o);
39 }
40 ll qu(int o,int l,int r,int p){
41     if(p<=0)return 0;
42     if(a[1].num<p)return 2e9;
43     if(l==r)return 1ll*l*p;
44     int m=(l+r)/2;
45     if(p<=a[ls].num)return qu(ls,l,m,p);
46     else return a[ls].sum+qu(rs,m+1,r,p-a[ls].num);
47 }
48 int main(){
49     scanf("%d",&M);
50     for(int i=1;i<=M;i++){
51         ll x,y;
52         scanf("%lld%lld",&x,&y);
53         if(!x){
54             start++;
55             continue;
56         }
57         q[x].push(y);
58         up(1,0,50000,y,1);
59         if(!vis[x]){
60             id[++cnt]=x;
61             vis[x]=1;
62         }
63     }
64     sort(id+1,id+1+cnt,cmp);
65     ll ans=1e18,res=0,num=0;
66     for(int i=M;i>=max(1ll,start);i--){
67         for(int j=1;j<=cnt;j++){
68             int x=id[j];
69             if(q[x].size()<i)break;
70             while(q[x].size()>=i){
71                 ll y=q[x].top();
72                 res+=y;
73                 up(1,0,50000,y,-1);
74                 q[x].pop();
75                 num++;
76             }
77         }
78         ll r=qu(1,0,50000,i-num-start);
79         ans=min(ans,res+r);
80     }
81     printf("%lld
",ans);
82 }

 

以上是关于51Nod 1494 选举拉票(权值线段树)的主要内容,如果未能解决你的问题,请参考以下文章

51nod1287(二分/线段树区间最值&单点更新)

51nod 1287 线段树

51nod1287(二分线段树)

51nod 1272 思维/线段树

51nod 1199 Money out of Thin Air(线段树+树剖分)

51Nod 1571 最近等对(线段树离线查询)