题意:有n座城池,m个人;

每座城池有一个耐久度;

每座城池有一个父亲城池(肯定会形成一棵树),还有flag base (这个看题意)

每个人有一个战力值和一个开始进攻的城池序号;

问:1.每个城池能够使将领死亡的死亡数 2.每个将领能够攻占的城池数量;

思路,这道题是一颗树,所以自然而然的想到用dfs传到根节点,再传回去这种做法;

那么在这种做法下,我们建立最小堆,对每一个节点建立一个最小堆,然后遍历的时候,将小于limit[]的将领弹出;

这个时候需要更新答案, 这个城池的将领死亡数量+1;这个将领攻占的城池数量;

然后   剩下的将领有一个val需要更新 这个时候我们不是直接更新,而是用一个懒惰节点去降低复杂度;

一步一步传给子节点更新;

 #include<cstdio>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
typedef long long ll;
const ll maxn=3e5+;
ll flag[maxn],base[maxn]; //城池的val更新方式
ll ch[maxn][]; //子节点
ll val[maxn],guishu[maxn]; //将领的战力值和第一个城池
ll root[maxn]; //每一个城池的根节点;
ll dep[maxn],dis[maxn]; //dep是用来计算将领的攻占城池数量的, dis是左偏树的深度;
ll ans1[maxn],ans2[maxn]; //城池答案,将领答案;
ll mul[maxn],add[maxn]; //懒惰标记
ll limit[maxn]; //城池耐久值
struct node //邻接表
{
ll v,next;
}G[maxn]; ll head[maxn];ll num=-;
void build(ll u,ll v)
{
G[++num].v=v;G[num].next=head[u];head[u]=num;
}
void cov(ll x,ll c,ll j)
{
if(!x) return;
val[x]*=c;val[x]+=j; //这里有一个乘和一个加,自然是先乘后加; 这是根据下文这两句来确定的
mul[x]*=c; //这里的确定方式是将已经有的懒惰节点的值与本次加进来的懒惰节点更新;
//已经有的,自然那些要+的,也要乘上这次的数,然后再加上这次要加的数
//注:下次看这里看不懂的话,多看一下肯定会懂的
add[x]*=c;add[x]+=j;
}
void pushdown(ll x)
{ //左右儿子都得更新
cov(ch[x][],mul[x],add[x]);
cov(ch[x][],mul[x],add[x]);
mul[x]=;add[x]=;
}
ll Merge(ll x,ll y)
{
if(!x||!y) return x+y;
pushdown(x);pushdown(y);
if(val[x]>val[y]) swap(x,y);
ch[x][]=Merge(ch[x][],y);
if(dis[ch[x][]]<dis[ch[x][]]) swap(ch[x][],ch[x][]);
dis[x]=dis[ch[x][]]+;
return x;
} void dfs(ll u,ll fa)
{
dep[u]=dep[fa]+;
for(ll i=head[u];i!=-;i=G[i].next){
ll v=G[i].v;
dfs(v,u);
root[u]=Merge(root[u],root[v]);
}
while(root[u]&&val[root[u]]<limit[u]){
pushdown(root[u]);
ans1[u]++;
ans2[root[u]]=dep[guishu[root[u]]]-dep[u];
ll t=root[u];
root[u]=Merge(ch[t][],ch[t][]);
}
if(flag[u]) cov(root[u],base[u],);
else cov(root[u],,base[u]);
}
int main()
{
ll n,m;
memset(head,-,sizeof(head));
scanf("%lld%lld",&n,&m);
for(ll i=;i<=n;i++) scanf("%lld",&limit[i]);
for(ll i=;i<=n;i++){
ll u;
scanf("%lld%lld%lld",&u,&flag[i],&base[i]);
build(u,i);
}
for(ll i=;i<=m;i++){
scanf("%lld%lld",&val[i],&guishu[i]);
ll t=guishu[i];
mul[i]=;
if(!root[t]) root[t]=i;
else root[t]=Merge(root[t],i);
}
dfs(,);
while(root[]){
pushdown(root[]);
ans2[root[]]=dep[guishu[root[]]];
root[]=Merge(ch[root[]][],ch[root[]][]);
}
for(ll i=;i<=n;i++) printf("%lld\n",ans1[i]);
for(ll i=;i<=n;i++) printf("%lld\n",ans2[i]);
return ;
}

左偏树 (p3261) 对我来说是一道进阶题的更多相关文章

  1. 洛谷P4331 [BOI2004] Sequence 数字序列 [左偏树]

    题目传送门 数字序列 题目描述 给定一个整数序列 a1​,a2​,⋅⋅⋅,an​ ,求出一个递增序列 b1​<b2​<⋅⋅⋅<bn​ ,使得序列 ai​ 和 bi​ 的各项之差的绝对 ...

  2. 【BZOJ2809】[APIO2012] dispatching(左偏树例题)

    点此看题面 大致题意: 有\(N\)名忍者,每名忍者有三个属性:上司\(B_i\),薪水\(C_i\)和领导力\(L_i\).你要选择一个忍者作为管理者,然后在所有被他管理的忍者中选择若干名忍者,使薪 ...

  3. 【左偏树】【P3261】 [JLOI2015]城池攻占

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

  4. BZOJ 4003 / Luogu P3261 [JLOI2015]城池攻占 (左偏树)

    左偏树裸题,在树上合并儿子传上来的堆,然后小于当前结点防御值的就pop掉,pop的时候统计答案. 修改的话就像平衡树一样打懒标记就行了. 具体见代码 CODE #include<bits/std ...

  5. [洛谷P3261] [JLOI2015]城池攻占(左偏树)

    不得不说,这道题目是真的难,真不愧它的“省选/NOI-”的紫色大火题!!! 花了我晚自习前半节课看题解,写代码,又花了我半节晚自习调代码,真的心态爆炸.基本上改得和题解完全一样了我才过了这道题!真的烦 ...

  6. P3261 [JLOI2015]城池攻占 (左偏树+标记下传)

    左偏树还是满足堆的性质,节点距离就是离最近的外节点(无左或者右儿子  或者二者都没有)的距离,左偏性质就是一个节点左儿子的距离不小于右儿子,由此得:节点距离等于右儿子的距离+1. 本题就是对于每个节点 ...

  7. 左偏树(Leftist Heap/Tree)简介及代码

    左偏树是一种常用的优先队列(堆)结构.与二叉堆相比,左偏树可以高效的实现两个堆的合并操作. 左偏树实现方便,编程复杂度低,而且有着不俗的效率表现. 它的一个常见应用就是与并查集结合使用.利用并查集确定 ...

  8. 『左偏树 Leftist Tree』

    新增一道例题 左偏树 Leftist Tree 这是一个由堆(优先队列)推广而来的神奇数据结构,我们先来了解一下它. 简单的来说,左偏树可以实现一般堆的所有功能,如查询最值,删除堆顶元素,加入新元素等 ...

  9. BZOJ2333 [SCOI2011]棘手的操作 堆 左偏树 可并堆

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2333 题意概括 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i ...

随机推荐

  1. 记录 Docker 的学习过程 (数据挂载)

    docker 存储篇 容器中的存储是分层的, 在容器中,如果我们要创建一个文件,会在文件的最上层(可写层)创建 容器中内置的文件,默认来讲是只读的,只有自己创建的文件才是可写状态 比如说 /etc/p ...

  2. Wannafly Camp 2020 Day 2H 叁佰爱抠的序列 - 欧拉遍历

    转化为完全图的欧拉遍历 如果 n 是奇数,则欧拉遍历长度为 \(n(n-1)/2\) 条边 如果 n 是偶数,则欧拉遍历长度为 \(n*n/2-1\) 条边 (即将(n-1)/2对点配对,剩下的一对当 ...

  3. Postgresql Json Sql

    a detailed website about json sql query; official website: here, chinese version: here Json query: - ...

  4. Python模块导入详解

    定义 模块:用来从逻辑上组织Python代码(变量.函数.类.逻辑)去实现一个功能.本质就是.py结尾的Python文件. 包:用来从逻辑上组织模块的(可以放一堆模块在目录下).本质就是一个目录(必须 ...

  5. c++中vector函数

    std::vector <cv::Point> VectorPoints 说明:首先定义一个Point(即Point2i---二维整型的点)类型的变量VectorPoints,这就是我们创 ...

  6. importing-cleaning-data-in-r-case-studies

    目录 importing-cleaning-data-in-r-case-studies 导入数据 查看数据结构 下面的一些都是查数据结构的 separate 拆分单元格 读取指定位置的数据 stri ...

  7. Python入门7 —— 赋值运算符补充

    增量赋值 x = 10 x += 1 #就是:x = x+1 交叉赋值 a = 10 b = 20 print(a,b) temp=b # temp=20 b=a # b = 10 a=temp # ...

  8. 自己动手系列----使用数组实现一个简单的Map

    数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同.Java 语言中提供的数组是用来存储固定大小的同类型元素. 这里提一下,数组的优缺点: 优点: 1. 使用索 ...

  9. Js 事件委托 解决动态元素不能click点击的问题

    参考教程地址 https://blog.csdn.net/xiaolong20081/article/details/79792137 不想写了.直接看上面就行 采用事件委托或代理方式绑定 $(doc ...

  10. 2019牛客训练赛第七场 C Governing sand 权值线段树+贪心

    Governing sand 题意 森林里有m种树木,每种树木有一定高度,并且砍掉他要消耗一定的代价,问消耗最少多少代价可以使得森林中最高的树木大于所有树的一半 分析 复杂度分析:n 1e5种树木,并 ...