51nod 1494 选举拉票 | 线段树
51nod1494 选举拉票
题面
现在你要竞选一个县的县长。你去对每一个选民进行了调查。你已经知道每一个人要选的人是谁,以及要花多少钱才能让这个人选你。现在你想要花最少的钱使得你当上县长。你当选的条件是你的票数比任何一个其它候选人的多(严格的多,不能和他们中最多的相等)。请计算一下最少要花多少钱。
Input
单组测试数据。
第一行有一个整数n (1 ≤ n ≤ 10^5),表示这个县的选民数目。
接下来有n行,每一行有两个整数ai 和 bi (0 ≤ ai ≤ 10^5; 0 ≤ bi ≤ 10^4),表示第i个选民选的是第ai号候选人,想要让他选择自己就要花bi的钱。你是0号候选人(所以,如果一个选民选你的话ai就是0,这个时候bi也肯定是0)。
Output
输出一个整数表示花费的最少的钱。
Input示例
5
1 2
1 2
1 2
2 1
0 0
Output示例
3
题解
啊……线段树……绝对要写完多检查一下……
不然会Debug De很久都De不出来……
长太息以掩涕兮……哀Bug之难De……
这道题和51nod的另一道题——稳定桌很相似。网上的题解把这类题归入“扫描线法”中。
具体做法:从大到小枚举你一共得到多少选票,然后分两步:选票比你多的人,你一定需要抢夺所有多出来的选票,当然,对每个人要抢他们手里最便宜的选票;如果抢完选票,当前选票数仍不够你枚举的选票数的话,就在所有不在你手中的选票中拣最便宜的抢。
注意抢夺选票这个过程是单向的,也就是你不可能把抢来的选票还回去。那么我们维护一个数据结构,支持求最小的k个数的和、支持删除一个数即可。我用的是线段树求第k大+树状数组求和。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
using namespace std;
typedef long long ll;
#define space putchar(' ')
#define enter putchar('\n')
#define INF 0x3f3f3f3f
template <class T>
bool read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
else if(c == EOF) return 0;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
return 0;
}
template <class T>
void write(T x){
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 200005;
struct people {
int a, b;
bool operator < (const people &obj) const{
return b < obj.b;
}
} peo[N];
int mx, n, ans = INF, adj[N], nxt[N], sze[N], pol[N];
int val[N], sum[4*N];
void add(int p, int x){
while(p <= n) val[p] += x, p += p & -p;
}
int ask(int p){
int ret = 0;
while(p) ret += val[p], p -= p & -p;
return ret;
}
void build(int k, int l, int r){
if(l == r) return (void)(sum[k] = 1);
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
sum[k] = sum[k << 1] + sum[k << 1 | 1];
}
void erase(int k, int l, int r, int p){
if(l == r) return (void)(sum[k] = 0);
int mid = (l + r) >> 1;
if(p <= mid) erase(k << 1, l, mid, p);
else erase(k << 1 | 1, mid + 1, r, p);
sum[k] = sum[k << 1] + sum[k << 1 | 1];
}
int query(int k, int l, int r, int p){
if(l == r) return l;
int mid = (l + r) >> 1;
if(sum[k << 1] >= p) return query(k << 1, l, mid, p);
else return query(k << 1 | 1, mid + 1, r, p - sum[k << 1]);
}
bool cmp(int a, int b){
return sze[a] < sze[b];
}
int main(){
read(n);
build(1, 1, n);
for(int i = 1; i <= n; i++)
read(peo[i].a), read(peo[i].b);
sort(peo + 1, peo + n + 1);
for(int i = n; i; i--){
nxt[i] = adj[peo[i].a];
adj[peo[i].a] = i;
sze[peo[i].a]++;
mx = max(mx, peo[i].a);
add(i, peo[i].b);
}
for(int i = 1; i <= mx; i++)
pol[i] = i;
sort(pol + 1, pol + mx + 1, cmp);
for(int tot = n, cost = 0, cnt = 0; tot >= 0; tot--){
for(int i = mx; i && sze[pol[i]] >= tot; i--)
for(int &e = adj[pol[i]]; e && sze[pol[i]] >= tot; e = nxt[e])
add(e, -peo[e].b), erase(1, 1, n, e), cost += peo[e].b, sze[pol[i]]--, cnt++;
if(cnt >= tot) ans = min(ans, cost);
else ans = min(ans, cost + ask(query(1, 1, n, tot - cnt)));
}
write(ans), enter;
return 0;
}
51nod 1494 选举拉票 | 线段树的更多相关文章
- 51nod 1494 选举拉票 (线段树+扫描线)
1494 选举拉票 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 收藏 关注 现在你要竞选一个县的县长.你去对每一个选民进 ...
- 51nod 1364 最大字典序排列(线段树)
1364 最大字典序排列基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 给出一个1至N的排列,允许你做不超过K次操作,每次操作可以将相邻的两个数交换,问能够得到的字 ...
- LightOJ 1370 Bi-shoe and Phi-shoe 欧拉函数+线段树
分析:对于每个数,找到欧拉函数值大于它的,且标号最小的,预处理欧拉函数,然后按值建线段树就可以了 #include <iostream> #include <stdio.h> ...
- loj1370(欧拉函数+线段树)
传送门:Bi-shoe and Phi-shoe 题意:给出多个n(1<=n<=1e6),求满足phi(x)>=n的最小的x之和. 分析:先预处理出1~1e6的欧拉函数,然后建立一颗 ...
- LOJ #2142. 「SHOI2017」相逢是问候(欧拉函数 + 线段树)
题意 给出一个长度为 \(n\) 的序列 \(\{a_i\}\) 以及一个数 \(p\) ,现在有 \(m\) 次操作,每次操作将 \([l, r]\) 区间内的 \(a_i\) 变成 \(c^{a_ ...
- 51nod 1463 找朋友(线段树+离线处理)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1463 题意: 思路: 好题! 先对所有查询进行离线处理,按照右区间排序, ...
- BZOJ 4034 树上操作(树的欧拉序列+线段树)
刷个清新的数据结构题爽一爽? 题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x ...
- [BZOJ4026]dC Loves Number Theory 欧拉函数+线段树
链接 题意:给定长度为 \(n\) 的序列 A,每次求区间 \([l,r]\) 的乘积的欧拉函数 题解 考虑离线怎么搞,将询问按右端点排序,然后按顺序扫这个序列 对于每个 \(A_i\) ,枚举它的质 ...
- BZOJ 4034 [HAOI2015]树上操作(欧拉序+线段树)
题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增 ...
随机推荐
- WebSocket抓包分析
转载自:https://www.cnblogs.com/songwenjie/p/8575579.html Chrome控制台 (1)F12进入控制台,点击Network,选中ws栏,注意选中Filt ...
- 从零开始的Python学习Episode 23——进程
---恢复内容开始--- 进程 由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程.Python提供了非常好用 ...
- 编译Android VNC Server
1,在如下地址checkout源代码,我checkout的版本为0.9.7http://code.google.com/p/android-vnc-server/source/checkout 2,在 ...
- python数据分析画图体验
对于numpy的函数,pands等,不是很熟,我来copy一下code,敲击一下,找找感觉. 默认的导入包import numpy as npimport matplotlib.pyplot as p ...
- Daily Scrum (2015/11/6)
今晚除了玉钟焕的其他成员在一起开了个短会.讨论有关添加新功能以及一些BUG问题.由于时间原因,我们本想把动态爬取功能留到第二个迭代中,但是现在目前时间还够,我们便一起对这一功能的讨论和实现进行分析. ...
- Spring笔记①--helloworld
Spring Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架,它主要是为了解决企业应用开发的复杂性而诞生的: 目的:解决企业应用开发的复杂性 功能:使用基本的Javabean ...
- 剑指offer:用两个栈实现队列
题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 思路: 可以用stack1来存所有入队的数.在出队操作中,首先将stack1中的元素清空,转移到sta ...
- 第一个Sprint冲刺成果
组长:李咏江,组员:叶煜稳,谢洪跃,周伟雄 进程:第一个算法功能完成
- PyCharm 配置远程python解释器和在本地修改服务器代码
PyCharm 配置远程python解释器和在本地修改服务器代码 最近在学习机器学习的过程中,常常需要将本地写的代码传到GPU服务器中,然后在服务器上运行.之前的做法一直是先在本地写好代码,然后通过F ...
- jquery 点击弹出层自身以外的任意位置,关闭弹出层
<!--弹出层---> <div class="mask"> <div class="wrap"></div&g ...