bzoj 4003: 城池攻占 左偏树
题目大意
题解
一开始看漏条件了
题目保证当占领城池可以使攻击力乘上\(v_i\)时,一定有\(v_i>0\)
上面这句话很重要(或者说去掉这句话就可以出成一道新题)
我们考虑在每个节点上都维护一个最小堆
每次移动时我们让在堆中的所有骑士一起移动
这样我们知道:如果堆顶的骑士可以占领成功
那么这个堆里剩下的所有骑士都一定能够占领成功
如果堆顶元素无法占领我们就删去这个堆顶的元素,这样我们最多删除n次
最坏情况是\(O(nlogn)\)的,可以承受
所以我们还需要这个堆支持快速合并,任意一个可并堆即可
于是我敲了一棵左偏树上去...打标记打到手软...第一次在堆上打标记
这个标记的正确性就由上面加粗的话保证了
这句话保证了:打标记后树的结构不会改变
调了1h才发现是merge没有return...
神奇的windows系统还让我过了样例和对拍,linux虚拟机下直接爆炸
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 300010;
struct Node{
Node *ch[2];
ll val,add,mul;
int cnt,tag,deg,id;
}*null;
Node mem[maxn<<1],*li;
Node *root[maxn];
inline void init(){
li = mem;null = li++;
null->ch[0] = null->ch[1] = null;
null->val = null->add = null->cnt
= null->tag = null->mul = 0;
}
inline Node* newNode(int id,ll val){
Node *p = li++;p->val = val;
p->ch[0] = p->ch[1] = null;
p->cnt = p->tag = p->deg = p->add = 0;
p->mul = 1;p->id = id;return p;
}
inline void pushdown(Node *p){
if(p == null) return;
if(p->ch[0] != null){
Node *x = p->ch[0];
if(p->mul != 1){x->mul *= p->mul;x->add *= p->mul;x->val *= p->mul;}
if(p->add != 0){x->add += p->add;x->val += p->add;}
if(p->tag != 0){x->tag += p->tag;x->cnt += p->tag;}
}
if(p->ch[1] != null){
Node *x = p->ch[1];
if(p->mul != 1){x->mul *= p->mul;x->add *= p->mul;x->val *= p->mul;}
if(p->add != 0){x->add += p->add;x->val += p->add;}
if(p->tag != 0){x->tag += p->tag;x->cnt += p->tag;}
}p->mul = 1;p->tag = p->add = 0;
}
Node *merge(Node *x,Node *y){
//printf("%d %d\n",x,y);
if(x == null) return y;
if(y == null) return x;
if(x->val > y->val) swap(x,y);
pushdown(x);
x->ch[1] = merge(x->ch[1],y);
if(x->ch[0]->deg < x->ch[1]->deg)
swap(x->ch[0],x->ch[1]);
x->deg = x->ch[1]->deg + 1;
return x;
}
int ans1[maxn],ans2[maxn];
inline void pop_less(int i,ll k,int p){
while(1){
if(root[i] == null) break;
if(root[i]->val >= k) break;
pushdown(root[i]);
ans2[root[i]->id] = root[i]->cnt;
//printf("%d died on %d with killed %d\n",root[i]->id,p,root[i]->cnt);
//printf("%lld <-> %lld\n",root[i]->val,k);
root[i] = merge(root[i]->ch[0],root[i]->ch[1]);
ans1[p]++;
}
}
ll h[maxn],v[maxn],s[maxn];
int c[maxn],fa[maxn],a[maxn];
inline void update(Node *p,int i){
//printf("update");
p->tag++;p->cnt++;
if(a[i] == 0){
p->add += v[i];
p->val += v[i];
}else{
p->mul *= v[i];
p->add *= v[i];
p->val *= v[i];
}
}
int main(){
init();
int n,m;read(n);read(m);
for(int i=1;i<=n;++i) read(h[i]),root[i] = null;
//printf("%d\n",root[2]);
for(int i=2;i<=n;++i){
read(fa[i]);read(a[i]);read(v[i]);
}
for(int i=1;i<=m;++i){
read(s[i]);read(c[i]);
if(s[i] < h[c[i]]){
ans1[c[i]]++;
ans2[i] = 0;
}else{
Node *p = newNode(i,s[i]);
update(p,c[i]);
root[c[i]] = merge(root[c[i]],p);
}
}
for(int i=n;i>=2;--i){
pop_less(i,h[fa[i]],fa[i]);
update(root[i],fa[i]);
root[fa[i]] = merge(root[i],root[fa[i]]);
}
while(root[1] != null){
pushdown(root[1]);
ans2[root[1]->id] = root[1]->cnt;
//printf("%d win with killed %d\n",root[1]->id,root[1]->cnt);
root[1] = merge(root[1]->ch[0],root[1]->ch[1]);
}
for(int i=1;i<=n;++i) printf("%d\n",ans1[i]);
for(int i=1;i<=m;++i) printf("%d\n",ans2[i]);
getchar();getchar();
return 0;
}
bzoj 4003: 城池攻占 左偏树的更多相关文章
- BZOJ 4003: [JLOI2015]城池攻占 左偏树 可并堆
https://www.lydsy.com/JudgeOnline/problem.php?id=4003 感觉就是……普通的堆啊(暴论),因为这个堆是通过递归往右堆里加一个新堆或者新节点的,所以要始 ...
- BZOJ 4003 / Luogu P3261 [JLOI2015]城池攻占 (左偏树)
左偏树裸题,在树上合并儿子传上来的堆,然后小于当前结点防御值的就pop掉,pop的时候统计答案. 修改的话就像平衡树一样打懒标记就行了. 具体见代码 CODE #include<bits/std ...
- [JLOI2015]城池攻占 左偏树
题目描述 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其中 fi &l ...
- [luogu3261 JLOI2015] 城池攻占 (左偏树+标记)
传送门 Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的 ...
- [洛谷P3261] [JLOI2015]城池攻占(左偏树)
不得不说,这道题目是真的难,真不愧它的“省选/NOI-”的紫色大火题!!! 花了我晚自习前半节课看题解,写代码,又花了我半节晚自习调代码,真的心态爆炸.基本上改得和题解完全一样了我才过了这道题!真的烦 ...
- bzoj 4003 [JLOI2015]城池攻占 —— 左偏树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4003 其实蛮简单的,首先一个城市只会被其子树中的骑士经过,启发我们 dfs 序用可并堆合并子 ...
- BZOJ4003 [JLOI2015]城池攻占 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4003 题意概括 题意有点复杂,直接放原题了. 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑 ...
- [BZOJ4003][JLOI2015]城池攻占(左偏树)
这题有多种做法,一种是倍增预处理出每个点往上走2^i步最少需要的初始战斗力,一种是裸的启发式合并带标记splay. 每个点合并能攻占其儿子的所有骑士,删去所有无法攻占这个城市的骑士并记录答案. 注意到 ...
- BZOJ 1455 罗马游戏 ——左偏树
[题目分析] 左偏树的模板题目,大概就是尽量维护树的深度保持平衡,以及尽可能的快速合并的一种堆. 感觉和启发式合并基本相同. 其实并没有快很多. 本人的左偏树代码自带大常数,借鉴请慎重 [代码] #i ...
随机推荐
- Windows系统的Jenkins持续集成环境
Windows系统的Jenkins持续集成环境 如题:本文将介绍如何在Windows环境下运用Jenkins部署持续集成环境.之所以写本文,是因为在最近工作当中,学习使用Jenkins时,确实遇到了一 ...
- 【selenium+python】自动化测试目录与文件结构
一.首先,看一下完整的项目目录结构图,如下: ==================目录结构================== ==================目录结构============== ...
- Android OkHttp的Cookie自己主动化管理
Android中在使用OkHttp这个库的时候.有时候须要持久化Cookie,那么怎么实现呢.OkHttp的内部源代码过于复杂,不进行深究.这里仅仅看当中的HttpEngineer里面的部分源代码,在 ...
- Loadrunner - Controller - policy - 设置集合点策略
控制器中设置集合点策略 我们在Virtual User Generator 中回放脚本无法 ...
- 【BZOJ3451】Tyvj1953 Normal 点分治+FFT+期望
[BZOJ3451]Tyvj1953 Normal Description 某天WJMZBMR学习了一个神奇的算法:树的点分治!这个算法的核心是这样的:消耗时间=0Solve(树 a) 消耗时间 += ...
- EasyRTMP+EasyDSS实现一套完整的紧急视频回传直播与存储回放方案
需求来源 紧急视频回传云端:即拍即传.云端存储.紧急录像.云拍云录!这些需求现在可能对于我们来说比较远,大部分也是在行业中才会用到,但相信在不就的将来肯定会落地到每个人的手中,因为这是一个自我保护.自 ...
- android菜鸟学习笔记3----关于AndroidMainfest.xml
每个android项目都包含一个AndroidMainfest.xml文件,它包含了组成应用程序的每一个Acitivity.Service.Content Provider和Broadcast Rec ...
- SD 相关表
一.客户主数据基本数据放在KNA1里:公司代码放在KNB1里:销售视图放在KNVV里:合作伙伴放在KNVP里: 二.信用主数据KNKK里有信贷限额.应收总额.特别往来:S066里是未清订单值:S067 ...
- ubuntu在vim里搜索关键字
在命令模式下敲斜杆( / )这时在状态栏(也就是屏幕左下脚)就出现了 “/” 然后输入你要查找的关键字敲回车就可以了. 如果你要继续查找此关键字,敲字符 n 就可以继续查找了.
- SNMP服务安装 Centos6.8环境网络安装
概念: snmp是英文“Simple Network Management Protocol”的缩写,意为:简单网络管理协议. snmp是目前最常用的环境管理协议. snmp被设计成与协议无关的. s ...