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. Oracle DELETE和TRUNCATE 的区别

    语法delete from aa truncate table aa 区别 1.delete from后面可以写条件,truncate不可以. 2.delete from记录是一条条删的,所删除的每行 ...

  2. redhat防火墙管理

    systemctl status firewalldsystemctl stop firewalldsystemctl start firewalldsystemctl enable firewall ...

  3. 三年同行,质造未来,腾讯WeTest五大服务免费体验

    WeTest 导读 2018年10月26日,腾讯WeTest将正式迎来三周岁生日.三周年庆典期间,只要在WeTest平台注册的用户,均可免费体验标准兼容.云真机.压测大师.手游安全扫描.应用安全扫描等 ...

  4. 【SpringCloud】 第十篇: 高可用的服务注册中心

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

  5. FU-A方式分包

    当 NALU 的长度超过 MTU 时, 就必须对 NALU 单元进行分片封包. 也称为 Fragmentation Units (FUs).  0 1  2 3 0 1 2 3 4 5 6 7 8 9 ...

  6. lesson 20 pioneer pilots

    lesson 20 Pioneer pilots driver pilot rider cyclist 骑自行车的人 介词后不加that cover + 距离 = travel 了一段距离 by su ...

  7. LeetCode - 566. Reshape the Matrix (C++) O(n)

    1. 题目大意 根据给定矩阵,重塑一个矩阵,r是所求矩阵的行数,c是所求矩阵的列数.如果给定矩阵和所求矩阵的数据个数不一样,那么返回原矩阵.否则,重塑矩阵.其中两个矩阵中的数据顺序不变(先行后列). ...

  8. hadoop问题集(2)

      28. Sqoop: java.lang.NullPointerException sqoop import --connect jdbc:oracle:thin:@//xxxx:1521/aps ...

  9. 团队Beta阶段事后分析

    团队Beta阶段事后分析 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件要解决用户的休闲娱乐问题,为用户提供好玩的模拟经营类的游戏,游戏主题 ...

  10. Calculator PartⅢ

    GitHub/object-oriented The title of the work 这次敲代码耗时相对较短,但是始终无法完成debug步骤,目前上传的代码可以通过编译,但运行即报停,问题调试为内 ...