zoukankan      html  css  js  c++  java
  • DAY 3

    DAY 3

    数据结构

    1.堆

    Priority_queue   大根堆

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

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

    它重载了运算符或函数类

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

    2.LCA(最近公共祖先)

    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])

    例题

    1.P3865 【模板】ST表

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int maxn=1e5+10,logN=20;
    int n,m;
    int a[maxn],logg[maxn]={-1};
    int f[maxn][logN+5]; 
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++)
          a[i]=read();
        for(int i=1;i<=n;i++)
        {
            f[i][0]=a[i];
            logg[i]=logg[i>>1]+1;
        }
          
        for(int j=1;j<=logN;j++)
          for(int i=1;i+(1<<j)-1<=n;i++)
            f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
        
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            int k=logg[y-x+1];
            printf("%d
    ",max(f[x][k],f[y-(1<<k)+1][k]));
        }
            
        return 0;
    }
    Code

    2.P2251 质量检测

    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdlib>
    #include<queue>
    
    using namespace std;
    
    inline int read()
    {
        int ans=0;
        char last=' ',ch=getchar();
        while(ch<'0'||ch>'9') last=ch,ch=getchar();
        while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
        if(last=='-') ans=-ans;
        return ans;
    }
    
    const int maxn=1e6+10,logN=20;
    int n,m;
    int a[maxn],q[maxn],logg[maxn]={-1};
    int f[maxn][logN+5];
    
    void ST()
    {
        for(int i=1;i<=n;i++)
        {
            f[i][0]=a[i];
            logg[i]=logg[i>>1]+1;
        }
        for(int j=1;j<=logN;j++)
          for(int i=1;i+(1<<j)-1<=n;i++)
            f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++)
          a[i]=read();
        ST();
        int k=logg[m];
        for(int i=1;i<=(n-m+1);i++)
        {
            int x=i,y=i+m-1;
            printf("%d
    ",min(f[x][k],f[y-(1<<k)+1][k]));
        }
        return 0;
    }
    Code

    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。
    • 枚举每个重心,以重心为根求出这棵有根树的最小表示,然后取字典序最大的即可。
    • 对于有根树的最小表示,可以看成括号序列,每次把子树的括号序列按字典序排序后依次串连起来即可。

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

     
     
  • 相关阅读:
    虚拟机类加载机制详解
    简单了解Tomcat与OSGi的类加载器架构
    Java高并发编程(四)
    Java高并发编程(三)
    Java高并发编程(一)
    垃圾收集与几种常用的垃圾收集算法
    初识java内存区域
    vue2.0基础学习(1)
    git/github 生成密钥
    手机预览vue项目
  • 原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/11191047.html
Copyright © 2011-2022 走看看