题意:有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. 百度网盘无vip高速下载的方法

    我拿的是谷歌浏览器做实验 首先下载一个可以改user-agent的插件 我chorm里面下载的是User-Agent Switcher for Chrome插件 将百度网盘的url地址中的baidu. ...

  2. Doing Homework HDU - 1074 状态压缩

    #include<iostream> #include<cstring> #include<cstdio> #include<string> #incl ...

  3. sqli-labs less-1 --> less-4

    Less-1  (报错注入) 因为第一次做这些题,不太了解,所以$sql下加上echo "$sql<br>";能更明显的看出具体的输入 1.判断是否存在注入点 当输入? ...

  4. <input type="file">文件上传

    <input> type 类型为 file 时使得用户可以选择一个或多个元素以提交表单的方式上传到服务器上,或者通过 Javascript 的 File API 对文件进行操作 . 常用i ...

  5. Spring域属性自动注入byName和byType

    byName 方式 <!--byName约束:bean当中的域属性名必须跟所注入bean的id相同--> <bean id="student" class=&qu ...

  6. 修复ThinkPHP导出excel数字过大时显示为科学记数法

    修复ThinkPHP导出excel数字过大时显示为科学记数法,这种显示对于查看的用户来说是及其不友好的.所以,我们要使其转化为正常的数字串! 我在google 的过程中,查了一些资料.其中 1).// ...

  7. S3C2440的时钟原理

    Crystal 无源晶体Oscillator 有源晶体(里面有有源器件) 无源晶振内只有一片按一定轴向切割的石英晶体薄片,供接入运放(或微处理器的XTAL端) 以形成振荡.有源晶振内带运放,工作在最佳 ...

  8. OpenGL 编程指南 (5.1)

    1.OpenGL支持同时使用多个纹理单元,使用GL_TEXTUREi进行标识,使用前需要先激活对应的纹理单元,默认GL_TEXTURE0是激活绑定的. void glActiveTexture(GLe ...

  9. oracle 数据库手动备份和恢复

    一.备份命令: 1.cmd  : exp 2.cmd  :用户名/密码@ip地址/数据库名  如:     yyj/yyj@172.12.5.5/orcl    要导出的数据库 3.回车:输入要输出的 ...

  10. Paper: ModelarDB

    Problem: how to store and querry massive amounts of high quality sensor data ingested in real-time f ...