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 的整数表示.除 ...
随机推荐
- 转:asp.net mvc ef 性能监控调试工具 MiniProfiler
MiniProfiler官网:http://miniprofiler.com/ MiniProfiler的一个特别有用的功能是它与数据库框架的集成.除了.NET原生的 DbConnection类,Mi ...
- 抽样分布(2) t分布
定义 t分布 设X ~ N(0,1),Y ~ χ2(n),且X,Y相互独立,则称随机变量 服从自由度为n的t分布(学生氏分布) 记为 t~t(n),其概率密度为 由于tn(x)是偶函数,其图形关于y轴 ...
- Entity Framework Core 选择数据表的外键
entityTypeBuilder .HasOne<GeraeteArt>() .WithMany(p => p.Geraete) .HasForeignKey(b => b. ...
- Qt-QML-Popup,弹层界面编写
随着接触Qt的时间的增加,也逐渐的发现了Qt 的一些不人信话的一些地方,不由的想起一句话,也不知道是在哪里看到的了“一切变成语言都是垃圾,就C++还可以凑合用”大致意思是这样.最近项目的祝界面框架都基 ...
- 七 Appium常用方法介绍
文本转自:http://www.cnblogs.com/sundalian/p/5629609.html 由于appium是扩展了Webdriver协议,所以可以使用webdriver提供的方法,比如 ...
- 通过 Python_Faker 生成测试数据
通过 Python_Faker 生成测试数据 一.介绍 在软件需求.开发.测试过程中,有时候需要使用一些测试数据,针对这种情况,我们一般要么使用已有的系统数据,你不可能通过手工来生成(最傻的方法)可能 ...
- Selenium 入门到精通系列:四
Selenium 入门到精通系列 PS:鼠标右键.鼠标悬停.键盘操作方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...
- Django学习总结①
Django基础环境配置好以后,打开pycharm,创建Django项目 视图views 中需要导入 django.http ---> HttpResponse models库 - 常用方法: ...
- 51单片机实现定时器00H-FFH、定时器000-255
#include< reg51.h> #define uint unsigned int #define uchar unsigned char sfr P0M0 = 0x94; sfr ...
- Multi-task Correlation Particle Filter for Robust Object Tracking--论文随笔
摘要:在这篇论文中,作者提出一种鲁棒视觉跟踪的多任务相关粒子滤波琪跟踪算法(MCPF).作者首先向我们展示了多任务相关滤波器,该滤波器在训练滤波器模板的时候可以学习不同特征之间的联系.本文提出的MCP ...