BZOJ4003:[JLOI2015]城池攻占——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4003
https://www.luogu.org/problemnew/show/P3261
小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池。这 n 个城池用 1 到 n 的整数表示。除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其中 fi <i。也就是说,所有城池构成了一棵有根树。这 m 个骑士用 1 到 m 的整数表示,其中第 i 个骑士的初始战斗力为 si,第一个攻击的城池为 ci。
每个城池有一个防御值 hi,如果一个骑士的战斗力大于等于城池的生命值,那么骑士就可以占领这座城池;否则占领失败,骑士将在这座城池牺牲。占领一个城池以后,骑士的战斗力将发生变化,然后继续攻击管辖这座城池的城池,直到占领 1 号城池,或牺牲为止。
除 1 号城池外,每个城池 i 会给出一个战斗力变化参数 ai;vi。若 ai =0,攻占城池 i 以后骑士战斗力会增加 vi;若 ai =1,攻占城池 i 以后,战斗力会乘以 vi。注意每个骑士是单独计算的。也就是说一个骑士攻击一座城池,不管结果如何,均不会影响其他骑士攻击这座城池的结果。
现在的问题是,对于每个城池,输出有多少个骑士在这里牺牲;对于每个骑士,输出他攻占的城池数量。
讲真,这题出在省选里就是为了卡掉一群不学左偏树的人。
题还真不难,左偏树比较裸的题。
暴力显然是O(nm)的。
但是如果我们对于每次模拟爬树的时候多让一些人跟着一起爬的话就能优化时间。
于是我们从叶子节点开始往根爬,把沿途节点的人合并到一起,维护一下这些人战斗力最小的那个,这样碰到城池打不破的时候弹掉最小的,直到最小的那个能打过了就是剩下的人都能打过了。
(当然说的那么简单你需要至少push两个lazy标记来更新战斗力,所以真恶心。)
分析复杂度(仅供参考因为我不会分析),最坏到最后一个人都没死,合并复杂度O(mlogm),弹出也是O(mlogm),只爬了一次树所以是O(n),于是整体复杂度就是O(mlogm)的了。
(当然这题你需要卡常技巧,洛谷一个点1s我卡了半个小时才过的……)
#include<cstdio>
#include<cmath>
#include<iostream>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
typedef long long ll;
const int N=3e5+;
inline ll read(){
ll x=,w=;char ch=;
while(ch<''||ch>''){if(ch=='-')w=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*w;
}
struct node{
int to,nxt;
}e[N];
struct tree{
int l,r,dis;
ll val;
}tr[N];
int head[N],cnt,die[N],knight[N],rt[N];
ll h[N],f[N],a[N],v[N],lazy[N][];
inline void add(int u,int v){
e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
inline void init(int x){
lazy[x][]=lazy[x][]=;
lazy[x][]=;
}
inline void push(int x){
if(!x)return;
if(tr[x].l){
tr[tr[x].l].val*=lazy[x][];tr[tr[x].l].val+=lazy[x][];
knight[tr[x].l]+=lazy[x][];
lazy[tr[x].l][]*=lazy[x][];lazy[tr[x].l][]*=lazy[x][];
lazy[tr[x].l][]+=lazy[x][];lazy[tr[x].l][]+=lazy[x][];
}
if(tr[x].r){
tr[tr[x].r].val*=lazy[x][];tr[tr[x].r].val+=lazy[x][];
knight[tr[x].r]+=lazy[x][];
lazy[tr[x].r][]*=lazy[x][];lazy[tr[x].r][]*=lazy[x][];
lazy[tr[x].r][]+=lazy[x][];lazy[tr[x].r][]+=lazy[x][];
}
init(x);
}
int merge(int x,int y){
if(!x||!y)return x+y;
push(x);push(y);
if(tr[x].val>tr[y].val)
swap(x,y);
tr[x].r=merge(tr[x].r,y);
if(tr[tr[x].l].dis<tr[tr[x].r].dis)
swap(tr[x].l,tr[x].r);
tr[x].dis=tr[tr[x].r].dis+;
return x;
}
int del(int x){
push(x);
return merge(tr[x].l,tr[x].r);
}
void dfs(int u){
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==f[u])continue;
dfs(v);
rt[u]=merge(rt[u],rt[v]);
}
while(rt[u]&&tr[rt[u]].val<h[u]){
die[u]++;
rt[u]=del(rt[u]);
}
if(rt[u]){
knight[rt[u]]++;
lazy[rt[u]][]++;
if(!a[u]){
tr[rt[u]].val+=v[u];
lazy[rt[u]][]+=v[u];
}
else{
tr[rt[u]].val*=v[u];
lazy[rt[u]][]*=v[u];
lazy[rt[u]][]*=v[u];
}
}
}
void upt(int x){
if(!x)return;
push(x);
upt(tr[x].l);upt(tr[x].r);
}
int main(){
int n=read(),m=read();
for(int i=;i<=n;i++)h[i]=read();
for(int i=;i<=n;i++){
f[i]=read(),a[i]=read(),v[i]=read();
add(f[i],i);
}
for(int i=;i<=m;i++)init(i);
for(int i=;i<=m;i++){
tr[i].val=read();
int c=read();
rt[c]=merge(i,rt[c]);
}
dfs();
upt(rt[]);
for(int i=;i<=n;i++)printf("%d\n",die[i]);
for(int i=;i<=n;i++)printf("%d\n",knight[i]);
return ;
}
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
BZOJ4003:[JLOI2015]城池攻占——题解的更多相关文章
- [bzoj4003][JLOI2015]城池攻占_左偏树
城池攻占 bzoj-4003 JLOI-2015 题目大意:一颗n个节点的有根数,m个有初始战斗力的骑士都站在节点上.每一个节点有一个standard,如果这个骑士的战斗力超过了这个门槛,他就会根据城 ...
- BZOJ4003 [JLOI2015]城池攻占 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4003 题意概括 题意有点复杂,直接放原题了. 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑 ...
- P3261 [JLOI2015]城池攻占 题解
题目 小铭铭最近获得了一副新的桌游,游戏中需要用 \(m\) 个骑士攻占 \(n\) 个城池.这 \(n\) 个城池用 \(1\) 到 \(n\) 的整数表示.除 \(1\) 号城池外,城池 \(i\ ...
- BZOJ4003[JLOI2015]城池攻占——可并堆
题目描述 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖, 其中 fi ...
- [BZOJ4003][JLOI2015]城池攻占(左偏树)
这题有多种做法,一种是倍增预处理出每个点往上走2^i步最少需要的初始战斗力,一种是裸的启发式合并带标记splay. 每个点合并能攻占其儿子的所有骑士,删去所有无法攻占这个城市的骑士并记录答案. 注意到 ...
- BZOJ4003 JLOI2015城池攻占
用左偏树模拟攻占的过程,维护最小值,最多入和出m次,每次log复杂度. #include<bits/stdc++.h> using namespace std; ; typedef lon ...
- BZOJ4003 [JLOI2015]城池攻占
这题有两种做法来着... 第一种就是一开始想到的比较不靠谱,不过貌似可以过掉: 看从$1$号节点开始到$p$号节点最大需要的体力,记录单调上升的体力,询问的时候二分跳着走就可以了 不过精度问题还有可能 ...
- 【BZOJ4003】[JLOI2015]城池攻占 可并堆
[BZOJ4003][JLOI2015]城池攻占 Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 1 号 ...
- BZOJ_4003_[JLOI2015]城池攻占_可并堆
BZOJ_4003_[JLOI2015]城池攻占_可并堆 Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 ...
随机推荐
- 这样的SQL居然能执行
select /*! distinct cities.id from cities join countries on cities.id = countries.id limit 10 */;
- 180605-Linux下Crontab实现定时任务
Linux下Crontab实现定时任务 基于Hexo搭建的个人博客,是一种静态博客页面,每次新增博文或者修改,都需要重新的编译并发布到Github,这样操作就有点蛋疼了,一个想法就自然而然的来了,能不 ...
- Selenium 入门到精通系列:四
Selenium 入门到精通系列 PS:鼠标右键.鼠标悬停.键盘操作方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...
- Selenium 入门到精通系列:二
Selenium 入门到精通系列 PS:用户登录 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019-04-23 16:12 ...
- TW实习日记:第22天
今天开发项目的还没完成的功能点,没什么难的,样式复制粘贴,JSON表单配一配,接口调一调,基本就完成了.不过中间在写后台的一些接口时,发现被自己之前写的一些方法给坑了.为什么这样说呢,因为在之前的几个 ...
- 使用js跳转手机站url的若干注意点
引子: 去年年底公司开发手机站平台,经历了前期的用户群.市场调查,产品需求分析,产品原型设计,ui前端到程序开发上线测试等等工作,终于上线...此处略去本人作为前端开发的心情. 应该说,我们的手机站平 ...
- java对json文件的操作
第一步:通过FileReader读取json文件第二步:使用BufferReader,先通过I/O读取一定大小的数据缓存到数组中,然后再从数组取出数据.第三步:用一个字符串把每次传来的数据处理后写到新 ...
- 利用AWS的EC2实例配合Putty访问Google账户
首先,我们需要一个amazon的帐号,该帐号可以开始AWS服务,第一次使用时需要绑定信用卡并扣1美元,然后再退还到我们的卡中,就是要验证一下信用卡帐户的有效性哦.有了这个帐号就可以尽情地享受AWS提供 ...
- python常用命令—‘\r’
# \r 默认表示将输出的内容返回到第一个指针,这样的话,后面的内容会覆盖前面的内容 如常用的显示程序完成进度!!
- usdt信息小结
https://blog.csdn.net/weixin_42208011/article/details/80499536 https://blog.csdn.net/weixin_42208011 ...