数据结构题大赏

偷走北大讲义

T1:紧急集合

【题目链接】

涉及主要算法:LCA;

SOLUTION:

求两两之间的LCA,取MIN就是最小的qwq;

求三个结点到一个结点距离之和最小的结点以及距离和

求出两两lca,其中有两个相同,答案则为另一个,画画图就可以理解

贴一篇blog

T2:中位数:

【题目链接】

维护两个堆,一个大根堆,一个小根堆;

对于序列:每新输入一个数,我们将之加入大根堆中,但大根堆不是无限加入的,我们设当前输入了k个数,那么大根堆中的元素至多有k/2 +1个,当大根堆中个数超过限制后,将堆顶移到小根堆,这样就可以保证大根堆堆顶永远是中位数;

next

合并果子:

【题目链接】

这个题就很水了;

haffman tree:每次将最小的两个合并,一定是最优的;

深度越深的节点,统计的次数越多;

因此越小的应该越先被合并;

题解:【堆】【洛谷例题】p1090 p1334 p1177

 滑雪等级Ski Course Rating:

【题目链接】

并查集问题:

  1. 将所有点,把边连出来
  2. 把所有边全删去(拿出来),按长度(高度差)从小到大排个序;
  3. 从小的边开始加,合并的同时统计这个集合大小,某一刻时,集合个数>=t时,最后一条边权就是难度等级D,然后ans+=D*集合个数???可能会有好多集合??

突然安利oj:

巴扎黑oj

树的同构:

【题目链接】

 一种暴力的想法:

 人为定义一个根,对于每个根,算出一个Hash来,如果有两棵树的Hash集合完全相同,那么这两棵树是同构的;

如何计算树形Hash:

把所有儿子的哈希值从大到小排个序,然后按字符串的方法来,计算当前节点的hash值;

一种很巧妙的算法:

重心:找到一个点为根,最大的一棵子树节点数最少;

每一棵无根树,重心个数不会超过二;

枚举每个重心,以重心为根求出这棵有根树的最小表示,然后取字典序最大的即可。

对于有根树的最小表示,可以看成括号序列,每次把子树的括号序列按字典序排序后依次串连起来即可。

有些许懵,嗯;

有关括号序列:

POJ 2299 Ultra-QuickSort

求逆序对数;

请用树状数组做;

用树状数组维护每个数之前有多少个大于它的数;

暴力O(n^2)

0 1 2 3 4 5 6 7 8 9……

开一个数据范围大小的数组用来维护当前每个数组出现了几次,然后我们需要求一个>当前数的数的个数,可以发现这是数组后缀,然后可以转化为总数- ≤当前数的个数;

举个亚子:

假设数据范围是9,我们开一个10个的数组,分别代表0~9,假设这个序列是19260817

 那么在插入0之前,序列:

0 1 2 3 4 5 6 7 8 9

0 1 1 0 0 0 0 0 0 1

此时我们插入0,我们需要寻找的是现在0之前插入的比0大的数,我们发现这是一个后缀问题,可以利用神仙操作将其转化为前缀。求出所有小于等于0的数,显然是0个,然后用当前插入的数的个数-0就是0的后缀;

然后可以用树状数组维护前缀和;

树状数组:动态将某个数+1,动态维护前缀和;

离散化:sort =>unique => 二分查找;

有关二维偏序:

xi≤xj

yi≤yj

ybt蓝书水题?!

按照y的升序(from small to big)处理;

建立一个树状数组,分别代表x为i的星星有多少个;

然后动态维护树状数组,对于每组数据,求出所有a≤当前x的数的个数(显然树状数组前缀和维护就好了);

即为答案level;

你看这个m超级小,一定有什么玄学?!

才华小哥哥上去分享,一语点不破梦中人;

开m个树状数组

每个树状数组都是0/1树状数组;

然后第i个树状数组第j个下标,表示a[j]%m==i?1:0;

下标为i的树状数组+x,把i+x%m置为1,把i%m的树状数组置为0;

思路1:把新插入的元素y插到set中,找到y的迭代器p,比较*(p++)和*(p--)与y的差值较小的就是波动√

思路2:维护一个线段树,求区间最大值和区间最小值

设每天的营业额在线段树数组中的下标为他本身的值

然后每次输入一个数时我们先在这个数的左边的区间查找最大值

再在右边的区间查找最小值

(这意味着我们要找比这个数小的最大值和比这个数大的最小值)

然后比较两者取差的绝对值最小的加到Ans里即可

看着就像线段树板子2;

单区间乘:

tag=1;开一个tag2表示加法lazy-tag

每次*c,tag*=c;sum*=c;tag*=c;

定义矩阵F=1 1  G=1

           1 0    1

Σi=l~r f(ai);

Σi=l~rFai*G=(Σi=l~rFai)*G;

对于区间l~r加上一个数x,相当于变成了*Fx

对于查询l~r,就是线段树查询出这个数。

 

这个题需要到叶子节点才能返回;,当某个节点为0或1时就不再更新了;

同样当某个区间全部为0或1时我们就不需要在将这个区间的数递归开根了,直接返回;

开一个数组s[5]={s0,s1,s2,s3,s4},分别代表集合l中%5余0,1,2 3,4,之和;

0 1 2 6 7 8 9

s:8,10,2,6,7  

Mex:最小的没有出现过的非负整数;

求出每个数组的前缀mex;

前缀mex:

19260817

00003333

拿走一个数x,在出现下一个x之前,所有前缀mex>x的都会被改变为x(区间修改去min)

然后添加一个数也随意?

枚举等差中项:

如果一个数出现过,位置为1,否则为0;每进入一个新数,把它枚举为等差数列中项,看现在以等差中项为对称轴的两侧是否对称(用hash来比较),说明这个等差中项不能产生等差数列,如果不对称,一定存在等差数列,直接输出yes;

 

posted @ 2019-07-16 20:17 Sweetness 阅读(...) 评论(...) 编辑 收藏