表示调这道题已经调到失智了。。。 因为昨天刚写完线段树2,所以pushdown就写得和线段树2一模一样,,,,于是,,,成功的在pushdown的地方,,,各种错

下面讲做法: 首先我们可以观察到每个骑士都是独立的,因此对于每个城池我们可以建一个堆,堆中维护的是在这个城池的骑士。

维护一个小根堆,所以如果堆顶的骑士攻击力不够的话,就可以直接pop掉,并且给城池死亡人数统计++(dead),这样用while pop完后,堆里的骑士就都是可以占领这个城池的了,

由于下面的骑士可以上来,所以这个堆要支持合并,所以我们用左偏树

因为pop完后剩下的都是合法的,所以这个时候我们就可以对剩下的骑士进行修改了。但是我们观察到,骑士很多,城池也很多,直接修改显然不太妥当。于是我们借鉴线段树的lazy标记,但是由于这里有乘法也有加法,所以我们维护两个标记,一个mul(乘法标记),一个lazy(加法标记),

由于(x+h)q=xq+hq,所以我们可以把h当做lazy,x当做当前值,q是mul,所以我们更改和下传乘法标记的时候,要同时把lazy也=mul,

这时lazy==hq,mul==q,因此我们要得到xq+h*q这个结果,我们需要先乘后加

deadin[i]代表骑士i死在哪里了,dead代表死在这个城池的人数,keep是城市的生命值,其他数组应该都好懂了

因为我们观察到如果还要下传一个标记won来标记骑士又占领了一个城池的话显然是不划算的,因为mul和lazy之所以有必要就是因为过程中要用到,而won标记仅仅是最后要用而已,并且由于骑士的前进路径是一条链,所以我们直接用死亡城市深度-出发城市深度就可以得到攻占几座城了,如果没死的话死亡城市就是0,因此为了维护死亡城市-出发城市这个式子的正确性,我们的deep统计从1开始

如果还有不懂的就看代码吧,还是有少量注释的

推荐写之前先写线段树2(luogu3373),有利于理解如何同时维护乘法和加法标记,这里的标记本质上是一样的,但是注意不要像我一样,写完线段树2,pushdown就全写成线段树版本的,,,,于是就各种错,,,

下面的输出格式是为了方便我调试改的,所以。。。。

写的可能比较复杂???

表示并不知道为什么我的代码一直比别人长。。。。

-------2018.10.11-------优化了代码格式

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 300050
  5 #define LL long long
  6 #define D printf("line in %d\n",__LINE__);
  7 int n, m;
  8 int date[AC], Next[AC], Head[AC], tot, cnt;//前向星
  9 LL v[AC], keep[AC];
 10 int deep[AC], a[AC], dead[AC], deadin[AC];//城池属性, 答案
 11 int b[AC], root[AC];
 12
 13 inline LL read()
 14 {
 15     LL x = 0; char c = getchar(); bool z = false;
 16     while(c > '9' || c < '0')
 17     {
 18         if(c == '-') z = true;
 19         c = getchar();
 20     }
 21     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
 22     if(!z) return x;
 23     else return -x;
 24 }
 25
 26 inline void add(int f, int w)
 27 {
 28     date[++tot] = w, Next[tot] = Head[f], Head[f] = tot;
 29 }
 30
 31 struct left_heap
 32 {
 33     LL s[AC], mul[AC], lazy[AC];//骑士属性和标记,error!!!标记也要LL啊啊啊啊啊啊啊啊,因为标记也可能乘到很大啊,比如lazy和mul各种乘之类的
 34     int l[AC], r[AC], num[AC];
 35
 36     inline void pushdown(int x)
 37     {
 38         int ll = l[x], rr = r[x];//error!!!这又不是线段树啊!!!!干嘛乘2啊
 39         if(!mul[x]) return ;//如果mul为0,说明没有这个堆,所以
 40         if(mul[x] != 1)
 41         {
 42             s[ll] *= mul[x], mul[ll] *= mul[x], lazy[ll] *= mul[x];//error!!!加法标记也要乘啊!!!
 43             s[rr] *= mul[x], mul[rr] *= mul[x], lazy[rr] *= mul[x];
 44             mul[x] = 1;
 45         }
 46         if(lazy[x])
 47         {
 48             s[ll] += lazy[x], lazy[ll] += lazy[x];
 49             s[rr] += lazy[x], lazy[rr] += lazy[x];
 50             lazy[x]=0;//error!!!不是线段树啊,,,,r,l不是区间了
 51         }
 52     }
 53
 54     inline void change_add(int x, int k)
 55     {
 56         if(!x) return ;
 57         s[x] += k, lazy[x] += k;
 58     }
 59
 60     inline void change_mul(int x, int k)
 61     {
 62         if(!x) return ;
 63         s[x] *= k, lazy[x]*=k, mul[x]*=k;
 64     }
 65
 66     int merge(int x, int y)
 67     {
 68         pushdown(x), pushdown(y);
 69         if(!x || !y) return x + y;
 70     //  pushdown(x),pushdown(y);
 71         if(s[x] > s[y]) swap(x, y);
 72         r[x] = merge(r[x], y);
 73         swap(l[x], r[x]);
 74         return x;
 75     }
 76
 77     void pop(int &x)
 78     {
 79         x=merge(l[x], r[x]);
 80     }
 81
 82     inline void insert(int x, int k)
 83     {
 84         s[++cnt] = x, num[cnt] = k, mul[cnt] = 1;
 85         root[b[k]] = merge(cnt, root[b[k]]);
 86     }
 87 }heap;
 88
 89 void DFS(int x)
 90 {
 91 /*  if(a[x]) heap.change_mul(root[x],v[x]);
 92     else heap.change_add(root[x],v[x]);
 93     if(!Head[x]) return ;//如果到叶节点就返回,因为没有儿子给它了
 94     */
 95     R now;
 96     for(R i = Head[x]; i; i = Next[i])
 97     {
 98
 99         now = date[i], deep[now] = deep[x] + 1;
100         DFS(now);
101         root[x] = heap.merge(root[now], root[x]);
102     }
103     while(root[x] && heap.s[root[x]] < keep[x])
104     {
105         dead[x] ++;
106         deadin[heap.num[root[x]]] = x;
107         heap.pop(root[x]);
108     }
109     if(a[x]) heap.change_mul(root[x], v[x]);
110     else heap.change_add(root[x], v[x]);
111 }
112
113 void pre()
114 {
115     int aa;
116     n = read(), m = read();
117     deep[1] = 1;
118     for(R i = 1; i <= n; i ++) keep[i] = read(), heap.mul[i] = 1;
119     for(R i = 2; i <= n; i ++)
120     {
121         aa = read(), a[i] = read(), v[i] = read();
122         add(aa, i);
123     }
124     for(R i = 1; i <= m; i ++)
125     {
126         aa = read(), b[i] = read();
127     //  printf("%d %d\n",aa,b[i]);
128         if(aa >= keep[b[i]])//如果第一座城池打得下才建堆
129         {
130             if(!root[b[i]])
131             {
132                 root[b[i]] = ++cnt;//应该要给城池开堆,堆里存士兵,不然士兵在哪个城市有上面区别
133                 heap.num[cnt] = i, heap.s[cnt] = aa, heap.mul[cnt] = 1;//因为是给城池开的堆,所以就要存编号了
134                 //printf("%d\n",i);
135             }
136             else heap.insert(aa, i);
137         }
138         else dead[b[i]] ++, deadin[i] = b[i];//不然就别来了
139     }
140 }
141
142 void work()
143 {
144     for(R i = 1; i <= n; i ++) printf("%d\n", dead[i]);
145     printf("\n");
146     for(R i = 1; i <= m; i ++)
147         printf("%d\n", deep[b[i]] - deep[deadin[i]]);
148 }
149
150 int main()
151 {
152     freopen("in.in","r",stdin);
153     pre();
154     DFS(1);
155     work();
156     fclose(stdin);
157     return 0;
158 }

View Code

转载于:https://www.cnblogs.com/ww3113306/p/8759040.html

[JLOI2015]城池攻占 左偏树相关推荐

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

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

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

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

  3. 【学习笔记】浅谈短小可爱的左偏树(可并堆)

    文章目录 左偏树 左偏树的合并(merge)操作 例题 罗马游戏 [Apio2012]dispatching [JLOI2015]城池攻占 [Baltic2004]sequence 左偏树 左偏树是一 ...

  4. 《程序设计解题策略》——1.6 利用左偏树实现优先队列的合并

    本节书摘来自华章计算机<程序设计解题策略>一书中的第1章,第1.6节,作者:吴永辉 王建德 更多章节内容可以访问云栖社区"华章计算机"公众号查看. 1.6 利用左偏树实 ...

  5. 【洛谷3377】 左偏树(可并堆)

    前言 其实我是不小心翻线性基的时候看见的. Solution 左偏树只会模板,挖坑待补 代码实现 #include<stdio.h> #include<stdlib.h> #i ...

  6. P3642 [APIO2016]烟火表演(左偏树、函数)

    解析 感觉是左偏树的神题了. 首先有一个比较显然的结论,一个合法的方案中,两个叶子到它们 lca\text{lca}lca 的距离必须相等. 考虑设计 dp\text{dp}dp : fi,xf_{i ...

  7. YbtOJ#631-次短路径【左偏树,最短路】

    正题 题目链接:https://www.ybtoj.com.cn/contest/114/problem/1 题目大意 给出nnn个点mmm条边的一张无向图,对于每个点iii求不经过i∼1i\sim ...

  8. P4331-[BalticOI2004]Sequence数字序列【左偏树】

    正题 题目链接:https://www.luogu.com.cn/problem/P4331 题目大意 给出一个序列aaa,求一个单调上升的序列bbb使得∑i=1n∣ai−bi∣\sum_{i=1}^ ...

  9. P1552-[APIO2012]派遣【左偏树】

    正题 题目链接:https://www.luogu.com.cn/problem/P1552 题目大意 一个nnn个点森林,每个点有价值和代价,选择一个点并在这个点的子树中选择一些点使得. 选择的点数 ...

  10. P3377-[模板]左偏树(可并堆)

    正题 题目链接:https://www.luogu.com.cn/problem/P3377 题目大意 开始时nnn个只有一个数的集合,要求支持 合并两个集合 查询一个集合中的最小值并删除 解题思路 ...

最新文章

  1. Zabbix(六):项目实战之--自动发现nginx调度器及后端web服务集群、自定义参数监控...
  2. 我也是一个线程,为什么每天累得像狗一样?
  3. 关于删除数据仓库的数据
  4. 初级数据分析师需要哪些必备技能?
  5. 做网站用UTF-8还是GB2312?
  6. 小波包能量matlab,小波包分析和小波包能量介绍.doc
  7. Redis简介及配置文件介绍
  8. 2018/7/31-zznuoj-问题 A: A + B 普拉斯【二维字符串+暴力模拟+考虑瑕疵的题意-0的特例】...
  9. c语言统计计算机专业人数,非计算机专业C语言练习题及2013版中国统计年鉴1.doc...
  10. docker 部署 gitlab最新版本( 当前 11.8.1通过验证)
  11. 优启通制作系统u盘_优启通 v3.6.2020.0620 VIP版/免费版-好用的U盘启动盘制作工具...
  12. GPS 经纬度换算方法和定位误差计算
  13. C#导出EXCEL没有网格线的解决方法
  14. Access键盘快捷键大全(一)
  15. Android 全仿To圈儿录音界面实现
  16. 将前端传过来的base64加密图片保存到本地,并且判断来自于哪个终端
  17. Machine Learning-L13-频繁模式挖掘
  18. Mac 使用音频工具分析音频数据
  19. 最简单的机器学习入门:线性回归
  20. 【Java容器】Java容器入门教程

热门文章

  1. C# 之 Stream 和 byte[] 的相关转换
  2. Nginx 笔记与总结(4)配置 server 访问日志
  3. Hadoop1.2.1源码解析系列:JT与TT之间的心跳通信机制——命令篇
  4. jQuery CSS 操作函数
  5. python源码中的学习笔记_第8章_函数
  6. 论文写不出来,导师放养,严重焦虑,怎么办?
  7. 【招聘】哈工大讯飞联合实验室2022届提前批校园招聘
  8. 【NLP 算法岗】提前批暑期实习面(试)经(历)
  9. 【收藏】这个时候才是最好的自学时间!深度学习-机器学习-GNN-NLP等AI课程超级大列表汇总,拿走不谢...
  10. 分类问题的label为啥必须是 one hot 形式?