最近一直在学图论,然后吧,由于学的东西实在是太多太杂了,加上蒟蒻本蒻又经常颓,所以落了好多好多板子题的整理没写啊嘤嘤嘤,不过把这些东西学的差不多了,再一块写个整理,其实感觉还不错?????也算是很神奇吧,大概就是知识的积淀这一块有了一点用

好了,话不多说,我们来进入正题

P3378 【模板】堆

我们从板子题入手,慢慢的了解堆(其实是自己巩固而已QWQ)

这里我们学习的堆其实是二叉堆,算是比较狭义的一种定义吧,首先,

堆是一种特殊的二叉树,而且是完全二叉树

为什么我们接触到的比较早的数据结构是堆呢?

其实有这么几个原因:

1.因为堆是一颗完全二叉树,所以在父亲和儿子方面,就完全不需要结构体存树,而是严格按照完全二叉树的定义来就可以

一棵树上的一个节点i,他的儿子是i*2和i*2+1,他的父亲是i/2(此处为整除)

所以处理的时候就很方便啊。

2.c++自带的STL对于堆非常友好,基本上随便写几个STL就能构建一个堆,即使是手写,大约时间也就是十分钟左右,并不是太慢。

3.堆的应用不少,比如堆排序,以及了解一种数据结构,为将来学习可并堆,斐波那契堆打下坚实基础,而且能优化dijkstra(图论).

下面来讲一讲堆的一些基本操作步骤

插入(大雾

我们要对堆插入一个元素,但是并不是扔进去,让尾指针++就完事了,我们还得对堆的正确性进行维护。

来说一下思想,对于添加进来的元素,设其位置为now,那么他爹就是now/2(now>>1  位运算更快哦)

只要比较二者大小,如果新元素更小,那么就交换即可,否则意味着合法,我们直接退出循环就可以,循环的终止条件就是now!=1(因为当now==1时,它已经是堆首元素,没爹。。。。多苦的一孩子(大雾)

来看代码

inline void add(int x)
{
Heap[++cnt] = x;//这里小小的压了一下行
int now = cnt;
while (now!=)
{
if (Heap[now] < Heap[now >> ])
swap(Heap[now], Heap[now >> ]),now>>=;
else
break;
}
}

弹出

这个也要分为两种,一种是弹出堆首元素,另一种是弹出任意位置的元素(这种一般与寻找元素相结合,考察对DFS,BFS之类的搜索方法的能力)

先看弹出堆首元素,

想要弹出的话,我们就把最小值修改为INF(我比较喜欢1e9),然后和之前相反,向下比较直到找到合适为止为止。

具体讲一讲

因为小根堆的要求是所有根节点都得比他孩子小,所以我们定义首节点的位置为root=1,因为已经置成INF了,所以我们向下开始比较;

先让两个孩子比,最小的那个再和root比,如果比root小,那么就交换二者,否则符合条件就直接退出循环,这里的循环终止条件是   root << 1 <= cnt,也就是说root的儿子已经比当前的堆的长度大了,也就是不存在儿子了

但是这种方法其实不是很好啊,因为你排到最后,最底下就一大堆INF,难看的要死还占空间,倒不如直接交换首元素和尾元素,然后直接把尾指针减一就可以,这样的话最小值就被删除了,之后进行一下动态维护就可以。

来看代码

inline void pop()
{
Heap[] = Heap[cnt--];
int root = ;
while (root << <= cnt)
{
int son;
if ((root << ) + > cnt ||
Heap[root << ] < Heap[(root << ) + ])
{
son = root << ;
}
else
son = (root << ) + ;
if (Heap[son] > Heap[root])
break;
swap(Heap[root], Heap[son]);
root = son;
}
}

输出堆首元素

这东西其实没啥好讲的,因为堆首元素就肯定是Heap[1]嘛,知道就行,然后就可以输出了,因为不对堆中元素进行移动和修改,是不影响堆的合法性的。

这些都看的差不多了,就直接略微修改,板子题就切掉啦

#include <iostream>
#include <queue>
#include <algorithm>
#include <cstdio>
using namespace std;
const int INF = ;
int n, a, b, Heap[], cnt = ;
inline void add(int x)
{
Heap[++cnt] = x;
int now = cnt;
while (now!=)
{
if (Heap[now] < Heap[now >> ])
swap(Heap[now], Heap[now >> ]),now>>=;
else
break;
}
}
inline void print()
{
printf("%d\n", Heap[]);
}
inline void pop()
{
Heap[] = Heap[cnt--];
int root = ;
while (root << <= cnt)
{
int son;
if ((root << ) + > cnt ||
Heap[root << ] < Heap[(root << ) + ])
{
son = root << ;
}
else
son = (root << ) + ;
if (Heap[son] > Heap[root])
break;
swap(Heap[root], Heap[son]);
root = son;
}
}
int main()
{
scanf("%d", &n);
for (int i = ; i <= n; ++i)
{
scanf("%d", &a);
if (a == )
{
scanf("%d", &b);
add(b);
}
if (a == )
print();
if (a == )
pop();
}
return ;
}

还是肥肠感谢gh神仙的热心帮忙啊,,,,QWQ一个板子题交了三四遍才过,真的是太辣鸡了

看完板子题,我们来看看合并果子这个题

P1090 合并果子

这个题在学完堆之后就好做多了,不过蒟蒻我很早以前做的时候是用dp加快排做的,那叫一个惨不忍睹啊,,,,,,,,连个样例都没过,所以干脆也就没有提交记录了

但是我们要分析分析,为什么这种算法会TLE

思考一下,我们对于,每一堆果子的个数进行排序,这样的话,先合并前两个果子,看似没什么问题,但是当你合并完了之后,你又得干啥呢???

我当时就傻乎乎的又用sort,然后就连本地编译都会超时,我们分析一下时间复杂度,其实就是O(nlongn+(n-1)log(n-1)+(n-2)log(n-2)+.....+log 1)

这样的话就肥肠慢了啊,因为每一次快排都是遍历了所有的数,但是其实很大一部分都是有序的,所以快排也没什么用,反而浪费时间。

那么用堆解决就没有任何问题了

每次合并前两个小的集合,然后把合并完的集合加到ans中,再扔回堆进行维护,这道题就做完啦

上代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,ans,Heap[],num,cnt=,sum;
inline void add(int x)
{
Heap[++cnt] = x;
int now = cnt;
while (now!=)
{
if (Heap[now] < Heap[now >> ])
swap(Heap[now], Heap[now >> ]),now>>=;
else
break;
}
}
inline void pop()
{
Heap[] = Heap[cnt--];
int root = ;
while (root << <= cnt)
{
int son;
if ((root << ) + > cnt ||
Heap[root << ] < Heap[(root << ) + ])
{
son = root << ;
}
else
son = (root << ) + ;
if (Heap[son] > Heap[root])
break;
swap(Heap[root], Heap[son]);
root = son;
}
}
int main()
{ scanf("%d",&n);
for(int i=;i<=n;++i)
{
scanf("%d",&num);
add(num);
}
while(cnt>=)
{
sum+=Heap[];
pop();
sum+=Heap[];
pop();
ans+=sum;
add(sum);
sum=;
}
printf("%d",ans);
return ;
}

想看堆排的同学看这里

堆以及一些用法 QWQ这是写得最认真的板子题的更多相关文章

  1. IOS Quartz 各种绘制图形用法---实现画图片、写文字、画线、椭圆、矩形、棱形等

    // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affec ...

  2. spm使用之六安装别人写好的spm文档主题模板

    上回说到有个nico-one的文档主题模板, https://github.com/lepture/nico-one 把他可以下载了, 放到 C:\Documents and Settings\Adm ...

  3. 在平衡树的海洋中畅游(四)——FHQ Treap

    Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...

  4. Luogu4081 USACO17DEC Standing Out from the Herd(广义后缀自动机)

    建出广义SAM,通过parent树对每个节点求出其是否仅被一个子串包含及被哪个包含. 写了无数个sam板子题一点意思都没啊 #include<bits/stdc++.h> using na ...

  5. 洛谷$P2168\ [NOI2015]$荷马史诗 贪心

    正解:贪心 解题报告: 传送门$QwQ$ 昂这个就哈夫曼树板子题鸭$QwQ$,只是从二叉变成多叉了$QwQ$ 考虑用类似合并果子的方法?就从两个变成$k$个了嘛,一样的鸭,然后就做完了$QwQ$ 注意 ...

  6. 洛谷$P$4137 $Rmq\ Problem / mex$ 主席树

    正解:主席树 解题报告: 传送门$QwQ$ 本来以为是道入门无脑板子题,,,然后康了眼数据范围发现并没有我想像的那么简单昂$kk$ 这时候看到$n$的范围不大,显然考虑离散化?但是又感觉似乎布星?因为 ...

  7. 自己动手写CPU——寄存器堆、数据存储器(基于FPGA与Verilog)

    上一篇写的是基本的设计方案,由于考研复习很忙,不知道下一次什么时候才能打开博客,今天就再写一篇.写一写CPU中涉及到RAM的部件,如寄存器堆.数据存储器等. 大家应该在大一刚接触到计算机的时候就知道R ...

  8. 如何获取JVM堆转储文件

    堆转储是诊断与内存相关的问题(例如内存泄漏缓慢,垃圾回收问题和 java.lang.OutOfMemoryError.它们也是优化内存消耗的重要工具. 有很多很不错的的工具,例如Eclipse MAT ...

  9. 【转载】Delphi异常处理try except语句和try finally语句用法以及区别

    Delphi异常处理try except语句和try finally语句用法以及区别 一直写程序都没管他们,也尽量很少用,今天终于想把他给弄个明白,在网上找来,记下!主要是前面小部分,后面的是详细说明 ...

随机推荐

  1. Scope 功能的改进

    前段时间发表了一篇文章 面向对象的一小步:添加 ActiveRecord 的 Scope 功能 提到一种更加友好的方式做数据库查询.经小伙伴的建议,在满足同样条件下,可以有更为简洁的封装方法. 这需要 ...

  2. 《JavaScript高级程序设计》笔记:BOM(八)

    BOM(浏览器对象模型)提供了很多对象,用于访问浏览器的功能,这些功能与任何网页内容无关. window对象 全局作用域 定义全局变量与在window对象上直接定义属性还是有一点差别:全局变量不能通过 ...

  3. Webpack4教程 - 第三部分,如何使用插件

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.原文出处:https://wanago.io/2018/07/23/webpack-4-course-part ...

  4. Android 最简单的测试UI卡顿

    就两个类: public class BlockDetectByPrinter { private static final String START = ">>>> ...

  5. Android 系统服务的获取与创建

    在Android系统中,有一群很厉害的“家伙”,如果把Android系统比喻成一个大帮派,那么这群“家伙”的地位就像那各个分堂的堂主一样,所有的应用就像是各个小马哥,他们要做什么事情,都要堂主审批,审 ...

  6. JS 引入方式 基本数据类型 运算符 控制语句 循环 异常

    一.JS引入方式 什么是JavaScript? JavaScript是运行在浏览器端的脚步语言,JavaScript主要解决的是前端与用户交互的问题,包括使用交互与数据交互,JavaScript是浏览 ...

  7. Powershell-远程操作

    1. 查看WinRM是否开启 Get-Service WinRM 2. Enable-PSRemoting –Force 3. 进行信任设置: Set-Item wsman:\localhost\cl ...

  8. struct导入项目工程时工程旁边出现红色的×号

    在我们学习java的过程中难免要导入java工程项目,那么当我们导进去的时候出现错误怎么办呢, 一,首先 二,其次 选择Properties 三,再选择 四,再选择 (高版本的选择1.5尽量用1.6的 ...

  9. ios copy和strong,浅拷贝和深拷贝

    copy@property (nonatomic, copy) NSString *name;self.name = mutableString;这时,name对mutableString一个深拷贝, ...

  10. day22 面向对象

    面向对象 ''''1.面向过程编程   核心是"过程"二字,过程指的是解决问题的步骤,即先干什么再干什么   基于该思想编写程序就好比在编写一条流水线,是一种机械式的思维方式​   ...