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

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

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. PHP 二维数组排序保持键名不变

    对二维数组指定的键名排序,首先大家想到的是array_multisort函数,关于array_multisort的用法我之前也写了一篇废话不多言,我们看个实例: <?php $data = ar ...

  2. java爬虫系列目录

    1. java爬虫系列第一讲-爬虫入门(爬取动作片列表) 2. java爬虫系列第二讲-爬取最新动作电影<海王>迅雷下载地址 3. java爬虫系列第三讲-获取页面中绝对路径的各种方法 4 ...

  3. H5、C3、ES6的新特性

    H5的新特性 1.语义化标签 有利于SEO,有助于爬虫抓取更多的有效信息,爬虫是依赖于标签来确定上下文和各个关键字的权重. 语义化的HTML在没有CSS的情况下也能呈现较好的内容结构与代码结构 方便其 ...

  4. 都 9012了,该选择 Angular、React,还是Vue?

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 尽管 Web开发的典型应用场景除了将服务器用作平台.浏览器用作客户端之外,几乎很少活跃于其他业务领域,但不可 ...

  5. SQL Server含逗号分隔的数据匹配维表

    日常有时候导出数据需求时,数据列会遇到带有分隔符的ID,但又需要匹配维表(如下图所示)将ID变成名称. 这种情况可以采用“分隔-匹配-合并”的方法 具体代码为: -- 准备工作1:创建事实表数据 CR ...

  6. Scrapy框架-Spider

    目录 1. Spider 2.Scrapy源代码 2.1. Scrapy主要属性和方法 3.parse()方法的工作机制 1. Spider Spider类定义了如何爬取某个(或某些)网站.包括了爬取 ...

  7. #035 大数阶乘 PTA题目6-10 阶乘计算升级版 (20 分)

    实际题目 本题要求实现一个打印非负整数阶乘的函数. 函数接口定义: void Print_Factorial ( const int N ); 其中N是用户传入的参数,其值不超过1000.如果N是非负 ...

  8. 【shell基础】if分支语句

    1.if判断式if [ 条件判断一 ] && (||) [ 条件判断二 ]; thenelif [ 条件判断三 ] && (||) [ 条件判断四 ]; thenels ...

  9. Linux云计算工程师

    一.Linux运维基础 二.Linux运维高级-核心知识提高 三.50台集群实战 四.200-1000台集群实战 五.shell编程企业级实战 六.数据库MySQL和NoSQL 七.LVM虚拟化和机房 ...

  10. 第一课android开发之在activity间传递参数

    一.活动间简单参数传递:1.在布局中添加按钮,用<Button,用id设置id名称,id="@+id/这儿填写你要设置成的名称":用text设置按钮上显示的文字.text=& ...