DAY 3 堆排序 P1090 合并果子 并查集 P3367 【模板】并查集 数据结构题目大赏 (一堆题目没做)

DAY 3

数据结构

1.堆

Priority_queue   大根堆

Priority_queue<int , vector<int> , greater<int> >  小根堆

支持插入一个值,删除最大/最小值

它重载了运算符或函数类

堆排序 P1090 合并果子    哈夫曼树

2.LCA(最近公共祖先)

局限于树,倍增大法好

我们有一棵树,定义某个点的祖先为这个点到根节点的路径上的所有点

对于点A,B,他们会有一些公共祖先

一旦找到LCA,他们的所有公共祖先都可找到,LCA一定是最深的公共祖先

用途找任意两点的最短路,AàLCA + BàLCA

步骤:

  1. 如果A的深度小于B的深度,就把他们交换(只是为了方便处理,跳较深的)

If( depA<depB) swap(A,B)

2.  把A,B调到同一深度

3.  A,B同时上调直到A=B,找到LCA

复杂度是O(dep)的,但是如果你的树是一条链,那么还不如不用

考虑优化

P[x][i],x的向上第2^i 个祖先

P[x][i]= P[P[x][i-1]][i-1]

(1)     优化:把A,B调到同一深度

我们发现A和B之间有深度差

比如 d[A]-d[B]=19

二级制分解19

19=10011

AàP[A][4]   16

AàP[A][1]   2

AàP[A][0]   1

(2)     优化:A,B同时上调

一开始A,B的祖先一直不一样,直到某个点,往后一样了就都一样了

我们不好确定最早的相同祖先的点,但是我们可以找到最后2个不相同祖先的x,y,那么此时,他们的父亲就会是LCA

For(i=16~0)

       If(f[A][i]!=f[B][i])

          A,B同时上跳2^i

复杂度O(logn)

LCA应用:

处理树上可以差分的信息

用到树上求A到B的最短路径:Aàgen +  Bàgen  -  2*LCAàgen

3.ST 表

只查询区间最大最小值,不修改,静态的

定义mx[i][j] 是 iài  +  2^j  -1 的最大值

如果要求区间[L,R]的最大值

比如区间 [19 46]

先求区间长度 46-19+1=28

发现它可以被两个16覆盖

PS:求区间最大值重叠不影响

覆盖区间长P=Floor(log2(L))

把[L,R]拆成两个区间 [L,P]和[R-2^P,R],分成两半分别处理

比如递归求解max

st[i][j] = max(st[i][j-1], st[i + (1 << j-1)][j-1])

4.HASH

是一种函数

平时说的HASH就是:设计一个函数F(字符串) à int ,就是把字符串变成数字,

map 基于比较函数的红黑树

如果你在map中放字符串,两个字符串比较的复杂度O(字符串长度)

所以要开发一种新的方法

假设给你一个字符串 ababb,1表示a,0表示b

10100

ababb

回忆初学二进制,用类似的方法计算出一个值

b*2^0+b*2^1+a*2^2+b*2^3+a*2^4    

HASH允许冲突,我们要尽量避免冲突,而不是根治冲突

给你一个乱码 yy1926

我们现在构造HASH

先确定几进制 P ,一个大质数,比字符串集大

那么计算它的值就是 6*p^0+2*p^1+9*p^2+1*p^3+y*p^4+y*p^5

前面数字还好啊,直接int计算了,那么对于字符呢??

取其ASCII码,mod 998244353  (一个大质数)

不过为了方便,可以直接开unsigned ll

Unsigned ll范围 0  ~  2^64  -1

你惊奇的发现2^64  -1是个质数

允许自然溢出,自然溢出相当于取模

用Unsigned ll存,用它计算,省去取模操作

为了避免冲突,你还可以取模两个数

HASH如何计算子串的hash?

希望设计一种算法,至少满足字符串拼接删除

比如现在有字符串 damengshen 和一个 p

d     d

di    d*p^1+i

din   d*p^2+i*p^1+n

ding  d*p^3+i*p^2+n*p^1+g

如果要求

ing的hash就是hash[ding]- hash[d]*p^3

ng的hash就是hash[ding]- hash[d]*p^2

我们维护了字符串每个前缀的hash值

发现p的指数难以确定,其实p的指数就是差的字符串的长度

令h[i]表示1~i的hash值

h[i]=h[i-1]*p+s[i]

hash[i][j]=h[j] - h[i-1]*p^(j-i+1)

5.并查集

没有必要保留树的结构,所以一个点的父亲可以直接指向它的代表源

路径压缩

  • int father(int x){
    • return fa[x]==x? x: fa[x]=father(fa[x]);
    • }

Father[x]à代表源

并查集 P3367 【模板】并查集

 

6.树状数组

int lowbit(int x){
    return x&(-x);
}

void modify(int x,int y){
    // add y to a[x]
    for(int i=x;i<=n;i+=lowbit(i)) c[i]+=y;
}

int query(int x){
    // sum of a[1]...a[x]
    int ret=0;
    for(int i=x;i;i-=lowbit(i)) ret+=c[i];
    return ret;
}

int query(int l,int r){
    return query(r)-query(l-1);
}
欣赏一下dms的代码

7.线段树

 例题:

1.P4281 [AHOI2008]紧急集合 / 聚会

  • 求三个结点到一个结点距离之和最小的结点以及距离和
  • 求出两两lca,其中有两个相同,答案则为另一个,画画图就可以理解

2.P1168 中位数

  对于给出的一个数列

 我们维护两个堆

大根堆堆顶维护中位数

考虑每次放两个数字进堆,比大根堆堆顶小的留在堆里,大的放到小根堆

一旦堆爆了,就把大根堆堆顶放到小根堆里啊

 3.P2168 [NOI2015]荷马史诗

   K叉哈夫曼树

   用堆维护

 4.P3101 [USACO14JAN]滑雪等级

 你考虑把所有点取出来,与周围点连边,边权就是这两点海拔高度差,然后考虑排个序

单独去除边,不连边,然后一个一个往里边加入边,合并两个点为一个集合,当有一个集合的边数>=T,就确定了整个集合的等级

5.P5043 【模板】树同构([BJOI2015]树的同构)

    对于每个点为根,求哈希

    如果两个哈希集合相同,那么他们同构

  • 树的HASH,如果两个哈希集合相同,那么他们同构
  • 对于一棵无根树,它的重心个数不超过2。
  • 枚举每个重心,以重心为根求出这棵有根树的最小表示,然后取字典序最大的即可。
  • 对于有根树的最小表示,可以看成括号序列,每次把子树的括号序列按字典序排序后依次串连起来即可。

数据结构题目大赏 (一堆题目没做)

 
 

猜你喜欢

转载自www.cnblogs.com/xiaoyezi-wink/p/11191047.html