https://scut.online/p/131

首先假如钦定了一群人去打怪兽,那么可以把主要的任务都丢给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 - 贪心 - 平衡树的更多相关文章

  1. JZOJ 5777. 【NOIP2008模拟】小x玩游戏

    5777. [NOIP2008模拟]小x玩游戏 (File IO): input:game.in output:game.out Time Limits: 1000 ms  Memory Limits ...

  2. 2783: 【基础】小 X 玩游戏(game)

    2783: [基础]小 X 玩游戏(game) 时间限制: 1 Sec 内存限制: 64 MB 提交: 752 解决: 294 [提交] [状态] [讨论版] [命题人:ghost79] 题目描述 听 ...

  3. P5676 [GZOI2017]小z玩游戏【Tarjan】

    小z玩游戏 Tarjan算是板子题吧,但是要稍微做一些修改,建边需要多考虑,建立"虚点". 题目描述 小 z 很无聊. 小 z 要玩游戏. 小 z 有\(N\)个新游戏,第\(i\ ...

  4. 力扣Leetcode 45. 跳跃游戏 II - 贪心思想

    这题是 55.跳跃游戏的升级版 力扣Leetcode 55. 跳跃游戏 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃 ...

  5. 【题解】 [GZOI2017]小z玩游戏

    题目戳我 \(\text{Solution:}\) 考虑建图.操作可以看作对\(1\)进行的操作,于是有以下运行过程: \(1\to w[i]\to e[i]\to...\) 考虑倍数,一个数可以走到 ...

  6. 神奇的建图方式(Tarjan)——小z玩游戏

    原题来自与:洛谷 P5676(GZOI2017)  链接: https://www.luogu.com.cn/problem/P5676 题面: 题意比较明显,如果已经建好了边,那么跑个Tarjan ...

  7. P5676 [GZOI2017]小z玩游戏 Tarjan+优化建图

    题目描述 分析 一开始看到这道题,首先想到的就是建好边后跑一个Tarjan缩点,将siz大于1的节点统计一下,输出结果 Tarjan非常显然易得,关键就是怎么建边 比较好想的一种思路就是枚举每一个兴奋 ...

  8. J - 玩游戏

    小A和小B玩游戏,初始的时候小A给小B一组包含n个数的数组.他们按如下的规则进行: 每次小B得到一组数,他把这组数的和加到自己的分数里面(他的初始分数是0),然后他把这组数还给小A. 如果小A得到的这 ...

  9. HihoCoder - 1615矩阵游戏II(贪心)

    矩阵游戏II 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个NxN的整数矩阵,小Hi每次操作可以选择两列,将这两列中的所有数变成它的相反数. 小Hi可以进行任意 ...

随机推荐

  1. vue-cli项目中引入全局scss

    加载一个全局设置文件 在每个组件里加载一个设置文件,而无需每次都将其显式导入,是一个常见的需求.比如为所有组件全局使用 scss 变量.为了达成此目的: npm install sass-resour ...

  2. windows10安装pycharm,以及pycharm教程和破解码

    pycharm下载请点我 根据自己的情况选择安装目录 下面我们选择"64位安装"(根据自己的系统来选择),并勾上".py",如图所示: 一定要拉到最后才行  p ...

  3. iOS---实现在屏幕上实时绘图的简单效果---CAShaperLayer和UIBezierPath的简单运用

    首先,声明几个属性 @property(nonatomic,strong)UIBezierPath * beizer; @property(nonatomic,assign)CGPoint start ...

  4. jq刷新页面

    //页面加载时绑定按钮点击事件$(function(){    $("#按钮id").click(function(){        refresh();    });});// ...

  5. 【bzoj3998】[TJOI2015]弦论

    题目描述: 对于一个给定长度为N的字符串,求它的第K小子串是什么. 样例输入: aabc 0 3 样例输出: aab 题解: 构造后缀自动机,然后在后缀自动机上跑dfs 代码: #include &l ...

  6. IOC和AOP使用扩展之AOP详解实现类

    摘要:   “Depend on yourself” is what nature says to every man.  Parents can help you. Teachers can hel ...

  7. git pull失误提交

    git pull 提示错误,Your local changes to the following files would be overwritten by merge 到公司后本来打算git pu ...

  8. [CSP-S模拟测试]:简单的操作(二分图+图的直径)

    题目描述 从前有个包含$n$个点,$m$条边,无自环和重边的无向图. 对于两个没有直接连边的点$u,v$,你可以将它们合并.具体来说,你可以删除$u,v$及所有以它们作为端点的边,然后加入一个新点$x ...

  9. #20175201张驰 实验三 敏捷开发与XP实践

    实验步骤 (一)敏捷开发与XP 一.敏捷开发与XP实践-1 ①实验要求: 敏捷开发与XP实践 http://www.cnblogs.com/rocedu/p/4795776.html, Eclipse ...

  10. Vuex的安装、使用及注意事项

    使用Vuex的步骤: (1)安装: 1.使用npm安装: 1 npm install vuex  --save 2.使用script标签引入 1 2 3 <script src="/p ...