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]城池攻占——题解的更多相关文章

  1. [bzoj4003][JLOI2015]城池攻占_左偏树

    城池攻占 bzoj-4003 JLOI-2015 题目大意:一颗n个节点的有根数,m个有初始战斗力的骑士都站在节点上.每一个节点有一个standard,如果这个骑士的战斗力超过了这个门槛,他就会根据城 ...

  2. BZOJ4003 [JLOI2015]城池攻占 左偏树 可并堆

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4003 题意概括 题意有点复杂,直接放原题了. 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑 ...

  3. P3261 [JLOI2015]城池攻占 题解

    题目 小铭铭最近获得了一副新的桌游,游戏中需要用 \(m\) 个骑士攻占 \(n\) 个城池.这 \(n\) 个城池用 \(1\) 到 \(n\) 的整数表示.除 \(1\) 号城池外,城池 \(i\ ...

  4. BZOJ4003[JLOI2015]城池攻占——可并堆

    题目描述 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖, 其中 fi ...

  5. [BZOJ4003][JLOI2015]城池攻占(左偏树)

    这题有多种做法,一种是倍增预处理出每个点往上走2^i步最少需要的初始战斗力,一种是裸的启发式合并带标记splay. 每个点合并能攻占其儿子的所有骑士,删去所有无法攻占这个城市的骑士并记录答案. 注意到 ...

  6. BZOJ4003 JLOI2015城池攻占

    用左偏树模拟攻占的过程,维护最小值,最多入和出m次,每次log复杂度. #include<bits/stdc++.h> using namespace std; ; typedef lon ...

  7. BZOJ4003 [JLOI2015]城池攻占

    这题有两种做法来着... 第一种就是一开始想到的比较不靠谱,不过貌似可以过掉: 看从$1$号节点开始到$p$号节点最大需要的体力,记录单调上升的体力,询问的时候二分跳着走就可以了 不过精度问题还有可能 ...

  8. 【BZOJ4003】[JLOI2015]城池攻占 可并堆

    [BZOJ4003][JLOI2015]城池攻占 Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 1 号 ...

  9. BZOJ_4003_[JLOI2015]城池攻占_可并堆

    BZOJ_4003_[JLOI2015]城池攻占_可并堆 Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池. 这 n 个城池用 1 到 n 的整数表示.除 ...

随机推荐

  1. angular ng-bind-html $sce.trustAsHtml

    使用ng-bind-html和$sce.trustAsHtml显示有html符号的内容   angularjs的强大之处之一在于它的双向数据绑定的功能,我们通常会使用data-ng-bind或者dat ...

  2. hive 更改列的位置时遇到的问题

    hive > desc formatted tb_fq; OK col_name data_type comment # col_name data_type comment name stri ...

  3. photoshop cc 2018安装破解教程(破解补丁,亲测,绝对可用)

    破解步骤说明:下载地址百度网盘,https://pan.baidu.com/s/1cWtpUesl2fms3tFwEC0MiQ 1.右键解压Adobe Photoshop CC 2018 64位这个文 ...

  4. Python Road

    引子 雁离群兮不知所归,路遥远兮吾将何往   Python Road[第一篇]:Python简介 Python Road[第二篇]:Python基本数据类型 Python Road[第三篇]:Pyth ...

  5. hdu1789 Doing Homework again(贪心+排序)

    Doing Homework again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  6. 【SpringCloud】 第九篇: 服务链路追踪(Spring Cloud Sleuth)

    前言: 必需学会SpringBoot基础知识 简介: spring cloud 为开发人员提供了快速构建分布式系统的一些工具,包括配置管理.服务发现.断路器.路由.微代理.事件总线.全局锁.决策竞选. ...

  7. 【system.date】使用说明

    对象:system.date 说明:提供一系列针对日期类型的操作 目录: 方法 返回 说明  system.date.isDate( date_string )  [True | False]  判断 ...

  8. jQuery实现仿京东商城图片放大镜

    效果图: 不废话直接上代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  9. postmortem report of period M2

    一.设想和目标 1.我们的软件主要要解决学长设计的学霸系统中视频及文档的浏览功能问题. 2.时间相对充裕.不过对于我们这些零基础的人来说还是比较困难. 3.我们团队中不同意见通常会进行进一步讨论,说出 ...

  10. lintcode-153-数字组合 II

    153-数字组合 II 给出一组候选数字(C)和目标数字(T),找出C中所有的组合,使组合中数字的和为T.C中每个数字在每个组合中只能使用一次. 注意事项 所有的数字(包括目标数字)均为正整数. 元素 ...