题意:有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. H3C接口管理配置

    一.接口批量配置 当多个接口需要配置某功能(比如shutdown)时,需要逐个进入接口视图,在每个接口执行一遍命令,比较繁琐.此时,可以使用接口批量配置功能,对接口进行批量配置,节省配置工作量. 1. ...

  2. ubuntu 开启对.htaccess的支持

    1. 终端运行    sudo a2enmod    程序提示可供激活的模块名称,输入:    rewrite    成功会提示 rewrite already load2. 修改/etc/apach ...

  3. Wannafly Camp 2020 Day 1C 染色图 - 组合数学,整除分块

    定义一张无向图 G=⟨V,E⟩ 是 k 可染色的当且仅当存在函数 f:V↦{1,2,⋯,k} 满足对于 G 中的任何一条边 (u,v),都有 f(u)≠f(v). 定义函数 g(n,k) 的值为所有包 ...

  4. [HNOI2003] 消防局的设立 - 树形dp

    仍然是点覆盖集问题,但覆盖半径变成了\(2\) 延续上一题的思路,只是式子更加复杂了 想体验一下min_element大法于是不想优化了 #include <bits/stdc++.h> ...

  5. C++中局部变量的返回

    在写 “根据中序和后序遍历顺序,构建树的问题” 时,原本这只是一个非常简单的问题,但是突然发现一直有错误.代码如下: node* get_root(int x1, int x2, int y1, in ...

  6. Linux C++ 直接选择排序,冒泡排序,快速排序

    选择排序的思想是:每次从待排序中选择最小(大)的元素插入已经排好的序列中. /*直接选择排序*/ #include <iostream> using namespace std; void ...

  7. <if test="type == '0' ">没有进去这个判断的问题

    在MyBatis的mapp文件中的if判断中是这样写的 <if test="type == '0' "> and so1.id = #{unitcode} </i ...

  8. JUC-线程间通信

    面试题: 两个线程,一个线程打印1-52,另一个打印字母A-Z打印顺序为12A34B...5152Z, 要求用线程间通信 线程间通信:1.生产者+消费者2.通知等待唤醒机制 多线程编程模版中 1.判断 ...

  9. Deepin安装常用软件

    Deepin安装常用软件 安装git sudo apt-get install git sudo是Debian系列以管理员运行的前缀 卸载软件 sudo apt-get remove package_ ...

  10. Java 中的 匿名类

    什么是内部类? 在一个类中定义另一个类,这样定义的类称为内部类.包含内部类的类称为内部类的外部类. 如果想要通过一个类来使用另一个类,可以定义为内部类. 内部类的外部类的成员变量在内部类仍然有效,内部 ...