SCUT - 131 - 小P玩游戏II - 贪心 - 平衡树
首先假如钦定了一群人去打怪兽,那么可以把主要的任务都丢给b最大的人去打,这样不会更差。然后考虑枚举这个b最大的人,其他人陪练。一开始就是ai+k*bi+sumC-ci,这个很好理解,然后这个人分出至多t=k-1个怪兽给陪练团打,那么既然规定陪练团每个人只能选1只去打,那么肯定是贪心选vj=aj+bj-cj最大的t个人去打。搞个Treap(随便,但是WA了好多发)维护一下。
注意是我这个模板居然没有初始化,草,还要自己写。但是Treap具体的原理并不是很明白。
注意的WA点在于找不超过k个人,且v要大于bi的那堆和。当右子树为空并不代表可以退出,或者说,当现在进入第二个分类里面的时候,有可能这里的子树是有用的。
看见别人直接二分找,内心是一千个草泥马。唉就当学习一下平衡树。
注意空间要开双倍,因为insert有两次。除非弄个回收?回收很好办的,实测省略一点点空间。因为经过直觉最多同时存在n个点所以直接这样就可以了:搞个STLstack(不能用数组否则不是浪费自己表情?)newnode的时候从stack里面删除,remove的时候把id放回stack里面。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 200000;
int ch[MAXN + 5][2];
int val[MAXN + 5], dat[MAXN + 5];
int siz[MAXN + 5], cnt[MAXN + 5];
ll sum[MAXN + 5];
int tot, root;
inline void Init() {
tot = 0;
root = 0;
}
inline int NewNode(int v) {
ch[++tot][0] = 0;
ch[tot][1] = 0;
val[tot] = v, dat[tot] = rand();
siz[tot] = 1, cnt[tot] = 1;
sum[tot] = v;
return tot;
}
inline void PushUp(int id) {
siz[id] = siz[ch[id][0]] + siz[ch[id][1]] + cnt[id];
sum[id] = sum[ch[id][0]] + sum[ch[id][1]] + 1ll * val[id] * cnt[id];
}
inline void Rotate(int &id, int d) {
int temp = ch[id][d ^ 1];
ch[id][d ^ 1] = ch[temp][d];
ch[temp][d] = id;
id = temp;
PushUp(ch[id][d]), PushUp(id);
}
inline void Insert(int &id, int v) {
if(!id)
id = NewNode(v);
else {
if(v == val[id])
++cnt[id];
else {
int d = v < val[id] ? 0 : 1;
Insert(ch[id][d], v);
if(dat[id] < dat[ch[id][d]])
Rotate(id, d ^ 1);
}
PushUp(id);
}
}
void Remove(int &id, int v) {
if(!id)
return;
else {
if(v == val[id]) {
if(cnt[id] > 1) {
cnt[id]--;
PushUp(id);
} else if(ch[id][0] || ch[id][1]) {
if(!ch[id][1] || dat[ch[id][0]] > dat[ch[id][1]])
Rotate(id, 1), Remove(ch[id][1], v);
else
Rotate(id, 0), Remove(ch[id][0], v);
PushUp(id);
} else
id = 0;
} else {
v < val[id] ? Remove(ch[id][0], v) : Remove(ch[id][1], v);
PushUp(id);
}
}
}
ll GetSum(int bi, int k) {
if(k == 0)
return 0;
//把大于bi的最大的至多k个v全部加起来,每加一个减去一个bi
int r = root;
ll res = 0;
while(r) {
if(bi >= val[r] || (ch[r][1] && siz[ch[r][1]] >= k)) {
//bi不比这个节点小,这个节点没用,向右走
//或者前k大完全在右子树中
r = ch[r][1];
continue;
} else {
//有用的完全在该节点及其右子树中
/*if(!ch[r][1])
return res;*/
res += sum[ch[r][1]];
res -= 1ll * siz[ch[r][1]] * bi;
k -= siz[ch[r][1]];
if(k <= cnt[r]) {
res += 1ll * k * (val[r] - bi);
k = 0;
return res;
}
else{
res += 1ll * cnt[r] * (val[r] - bi);
k -=cnt[r];
}
r=ch[r][0];
}
}
return res;
}
int n, k;
struct Char {
int a, b, c;
int v;
Char() {};
Char(int _a, int _b, int _c) {
a = _a;
b = _b;
c = _c;
v = a + b - c;
}
} cha[100005];
ll sumC;
ll calc(int id) {
ll M = sumC - cha[id].c + cha[id].a + 1ll * k * cha[id].b ;
Remove(root, cha[id].v);
//至多从平衡树拿走k-1个
ll res = GetSum(cha[id].b, k - 1);
Insert(root, cha[id].v);
return M + res;
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &k);
sumC = 0;
Init();
for(int i = 1; i <= n; ++i) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
cha[i] = Char(a, b, c);
sumC += c;
Insert(root, cha[i].v);
}
ll ans = 0;
for(int i = 1; i <= n; ++i)
ans = max(ans, calc(i));
printf("%lld\n", ans);
}
return 0;
}
SCUT - 131 - 小P玩游戏II - 贪心 - 平衡树的更多相关文章
- JZOJ 5777. 【NOIP2008模拟】小x玩游戏
5777. [NOIP2008模拟]小x玩游戏 (File IO): input:game.in output:game.out Time Limits: 1000 ms Memory Limits ...
- 2783: 【基础】小 X 玩游戏(game)
2783: [基础]小 X 玩游戏(game) 时间限制: 1 Sec 内存限制: 64 MB 提交: 752 解决: 294 [提交] [状态] [讨论版] [命题人:ghost79] 题目描述 听 ...
- P5676 [GZOI2017]小z玩游戏【Tarjan】
小z玩游戏 Tarjan算是板子题吧,但是要稍微做一些修改,建边需要多考虑,建立"虚点". 题目描述 小 z 很无聊. 小 z 要玩游戏. 小 z 有\(N\)个新游戏,第\(i\ ...
- 力扣Leetcode 45. 跳跃游戏 II - 贪心思想
这题是 55.跳跃游戏的升级版 力扣Leetcode 55. 跳跃游戏 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃 ...
- 【题解】 [GZOI2017]小z玩游戏
题目戳我 \(\text{Solution:}\) 考虑建图.操作可以看作对\(1\)进行的操作,于是有以下运行过程: \(1\to w[i]\to e[i]\to...\) 考虑倍数,一个数可以走到 ...
- 神奇的建图方式(Tarjan)——小z玩游戏
原题来自与:洛谷 P5676(GZOI2017) 链接: https://www.luogu.com.cn/problem/P5676 题面: 题意比较明显,如果已经建好了边,那么跑个Tarjan ...
- P5676 [GZOI2017]小z玩游戏 Tarjan+优化建图
题目描述 分析 一开始看到这道题,首先想到的就是建好边后跑一个Tarjan缩点,将siz大于1的节点统计一下,输出结果 Tarjan非常显然易得,关键就是怎么建边 比较好想的一种思路就是枚举每一个兴奋 ...
- J - 玩游戏
小A和小B玩游戏,初始的时候小A给小B一组包含n个数的数组.他们按如下的规则进行: 每次小B得到一组数,他把这组数的和加到自己的分数里面(他的初始分数是0),然后他把这组数还给小A. 如果小A得到的这 ...
- HihoCoder - 1615矩阵游戏II(贪心)
矩阵游戏II 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个NxN的整数矩阵,小Hi每次操作可以选择两列,将这两列中的所有数变成它的相反数. 小Hi可以进行任意 ...
随机推荐
- vue-cli项目中引入全局scss
加载一个全局设置文件 在每个组件里加载一个设置文件,而无需每次都将其显式导入,是一个常见的需求.比如为所有组件全局使用 scss 变量.为了达成此目的: npm install sass-resour ...
- windows10安装pycharm,以及pycharm教程和破解码
pycharm下载请点我 根据自己的情况选择安装目录 下面我们选择"64位安装"(根据自己的系统来选择),并勾上".py",如图所示: 一定要拉到最后才行 p ...
- iOS---实现在屏幕上实时绘图的简单效果---CAShaperLayer和UIBezierPath的简单运用
首先,声明几个属性 @property(nonatomic,strong)UIBezierPath * beizer; @property(nonatomic,assign)CGPoint start ...
- jq刷新页面
//页面加载时绑定按钮点击事件$(function(){ $("#按钮id").click(function(){ refresh(); });});// ...
- 【bzoj3998】[TJOI2015]弦论
题目描述: 对于一个给定长度为N的字符串,求它的第K小子串是什么. 样例输入: aabc 0 3 样例输出: aab 题解: 构造后缀自动机,然后在后缀自动机上跑dfs 代码: #include &l ...
- IOC和AOP使用扩展之AOP详解实现类
摘要: “Depend on yourself” is what nature says to every man. Parents can help you. Teachers can hel ...
- git pull失误提交
git pull 提示错误,Your local changes to the following files would be overwritten by merge 到公司后本来打算git pu ...
- [CSP-S模拟测试]:简单的操作(二分图+图的直径)
题目描述 从前有个包含$n$个点,$m$条边,无自环和重边的无向图. 对于两个没有直接连边的点$u,v$,你可以将它们合并.具体来说,你可以删除$u,v$及所有以它们作为端点的边,然后加入一个新点$x ...
- #20175201张驰 实验三 敏捷开发与XP实践
实验步骤 (一)敏捷开发与XP 一.敏捷开发与XP实践-1 ①实验要求: 敏捷开发与XP实践 http://www.cnblogs.com/rocedu/p/4795776.html, Eclipse ...
- Vuex的安装、使用及注意事项
使用Vuex的步骤: (1)安装: 1.使用npm安装: 1 npm install vuex --save 2.使用script标签引入 1 2 3 <script src="/p ...