zoukankan      html  css  js  c++  java
  • CCPC-wannafly Camp Day2 讲课内容总结(杜瑜皓-数据结构)

    ·栈、单调栈

    1.栈的特点与基本操作

    2.单调栈

    单调栈是一种特殊的栈,其栈内的元素都保持一个单调性(单调递增或者递减)。

      ·单调递增栈,从栈底到栈顶依次递增(单调非递减栈:允许有相等)

      ·单调递减栈,从栈底到栈顶依次递减(单调非递增栈:允许有相等)

    qes1.给一个序列,求对于每个数左边第一个比它大的数

    做法:维护一个单调栈

    ①如果当前栈顶的元素比自己小,则将栈顶元素不断弹出,直到遇到第一个比自己大的元素,即为左边第一个比自己大的数

    ②如果一直弹出直到栈空了,则无法找到左边比自己大的元素

    ③将自己加入栈顶

    更具体做法可参见:https://blog.csdn.net/Floraqiu/article/details/81947461

    ·笛卡尔树

    qes1.求每段区间最小值的和

    做法:笛卡尔树

    一些性质:

    ①堆的性质,小根堆,两子的值大于等于父亲的值

    ②二叉搜索树性质,即左子树的点key(默认为下标)比根小,右子树的点key(默认为下标)比根大显然(增量法构造),按中序遍历这棵树,可得原序列

    ③询问下标i到下标j之间(i<j)的最小值,只需寻找[i,j]的lca

    ④修改只会在最右边的一条链上修改,左子树不会再修改。并且右边的链相当于一个栈,出栈的元素进入左子树

    以某元素为最小值的区间长度为:(sizeL+1)*(sizeR+1

    参考链接:https://blog.csdn.net/Code92007/article/details/94591571

    ·队列、单调队列

    qes1.求所有区间长度为k的区间的最大值

    做法:单调队列(与单调栈类似)

    ①插入:若新元素从队尾插入后会破坏单调性,则删除队尾元素,直到插入后不再破坏单调性为止,再将其插入单调队列。

    ②获取最优(最大、最小)值:访问首尾元素

    ③队首元素超过其存活期则应该弹出 

    ·STL

    1.Vecotor,stack,queue

    2.set,map,priority_queue

    ①set支持insert(),erase()操作

    ②upper_bound(),lower_bound()不可直接使用,要加上s.lower_bound()

    ③map<int,int> x  等价于  set<pair<int,int>>

    3.multiset

    ①支持可重复元素

    ②erase()操作删除所有相同的元素

    ③ 对于序列[1,1,2,3,4,4,5] :lower_bound()找到第一个4,upper_bound()找到第二个4

    ④对于③中的序列要想只删除多个4中的一个:s.earse(lower_bound(4))

    4.unordered_map,unordered_set

    ①无法使用upper_bound()与lower_bound()

    ②可在o(1)复杂度内询问元素是否在集合内(本质为哈希表)

    qes1.维护一个几个集合,支持插入一个数,删除一个数,求所有数从小到大排序之后的异或和

    做法:先将所有元素排序,之后将两两相邻的元素的异或关系加入集合中

         删除:将被与删除元素与其相连的两个元素之间的关系删除,再加入与其相连的两个元素新形成的关系

         插入:用lower_bound()找到元素对应位置,删除原先的关系,加入新的关系

    ·树上倍增

    qes1.求一个点往上第K个祖先

    做法:树上倍增

    定义数组fa[i][j]表示i节点的第2^j个父亲是谁。

    然后,我们会发现有这么一个性质:

                           fa[i][j]=fa[fa[i][j-1]][j-1]

            用文字叙述为:i的第2^j个父亲 是i的第2^(j-1)个父亲的第2^(j-1)个父亲

    例.假设求u的第11个父亲:

    ①将11转化为二进制1011

    ②u->f(u,3)->f(u,1)->f(u,0)

    qes2.求LCA

    ①如果两点高度(即深度)相同

    for k = log(n) to 0

      if f(u,k)=f(v,k)

        continue

      else

        u=f(u,k)

        v=f(v,k)

    ②如果两点高度不相同,先将低的点跳到与高的点深度相同

    qes3.求两点之间路径的最大值

    思路:倍增的同时记录下g(u,j)=max(g(u,j-1),g((f(u,j-1),j-1))

    qes4.有若干个操作,每次将一条路径上的边全部加上一个值,操作完之后求每条边的权值

    与qes3类似,所有可以合并的信息都能用点三的信息求出

    ·ST表

    1.RMQ

    一个高效的用于查询区间最大/最小值的方法,其需要O(nlogn))的时间复杂度进行预处理,之后对于每次的区间查询的复杂度为O(1)。

    预处理

    设mn[i][j]表示从第i位开始连续2^j个数中的最小值。例如mn[2][1]为第2位数开始连续2个的数的最小值,即3, 6之间的最小值,即mn[2][1] = 3;

    之后我们很容想到递推方程:

    mn[i][j] = min(mn[i][j - 1], mn[i + (1 << j - 1)][j - 1])

    查询

    假设我们需要查询区间[l, r]中的最小值,令k = log2(r - l + 1); 则区间[l, r]的最小值RMQ[l,r] = min(mn[l][k], mn[r - (1 << k) + 1][k]);

    2.RMQ求LCA

    ①概念
      时间戳 - 该结点dfs首次遍历到的序号,用dfn记录。
      欧拉序 - dfs遍历节点,节点的编号形成的序列,用ol记录。(包括回溯)

    ②在欧拉序上进行RMQ:

    depth[i][j]表示从i开始包括自身在内的2^j个节点中的深度最小值,
    id[i][j]表示与depth[i][j]对应的节点编号,也就是这2^j个节点的LCA。
    LCA在ol[dfn[x]],ol[dfn[y]]之间(闭区间)且是其中深度最小的节点,这是显然的:(设 dfn[x] < dfn[y]
    (x,y)有两种情况,xy的祖先,此时向下遍历一定会到达y
    x不是y的祖先,由于树上路径x,y的唯一性,在到达x后必然会退出x,经过LCA(x,y),到达y
    三.二维RMQ
    ·分治
    思路:将一个大问题分成若干个小问题进行求解
    qes1.有一个n*n的矩阵,我们知道每一行最小值的位置单调不降,求每一行最小值的位置
    解法:该问题是一个决策单调性问题,我们可以先O(N)暴力找到中间一行的最小值位置,再用分治缩短两边的最小值位置求解
    伪代码:
    solve(l,r,a,b)  //代表从l-r行,a-b列
      mid=(l+r)>>1
      for i= a:b
        find(pos) //找到最小值的位置
      if l≤mid-1
        solve(l,mid-1,a,pos)
      if r≥mid+1
        solve(mid+1,r,pos,b)
    ·线段树
    帖一篇的博客:https://www.cnblogs.com/AC-King/p/7789013.html
    qes1.一个序列,支持区间加,区间乘,区间求和
    难点在于怎么同时维护区间乘与区间加的标记
    有点忘了咋做了妈的,就先不写了,依稀记得乘法优先级最高啥的,找了半天博客也没找到怎么写,有遇到具体的题再补吧日
    qes2.平面上有n个点,每次询问为一个矩形内有多少个点,允许离线
    做法:扫描线
    先将所有询问读入,然后按坐标的某一维排序,另一边维加点边查询
    qes3.给一个序列,支持区间加,询问区间第一个大于k的数字
    做法:线段树上二分,二分区间的位置(后来回去觉得有些奇怪啊,区间又不是有序的咋排序啊,但是dls是这么说的)
    qes4.一个长度为n的全排列,进行m次操作,每次操作是把[L,R]这个区间变成升序或降序,求m次操作后x这个位置的数
    dls没讲这道题QAQ,希望以后能想出来
    ·启发式合并
    qes1.有若干个集合,支持两个集合合并,求第k大

    ①先将所有集合内部排序

    ②每次暴力合并把小集合的合并到大的里

    看起来很暴力的一个做法,但是时间复杂度只有(nlogn)

    伪代码:

     merge(a,b)

      size(a)>size(b) //交换两个集合a.swap(b)

        for x :b

          a.insert(b)

    qes2.求出每个子树的众数

    做法:DSU On Tree(树上启发式合并),dfs到某一个点,将其子树的所有点合并,求集合中的众数

       子树问题:一个元素都是单独的一个集合

    伪代码:

      dfs(u)

      Sa={Bu}

      for v:son[u]

        dfs(v)

        su=Sa U Sv

    ·Segement  beats(吉如一线段树)

    详细博客:https://oi-wiki.org/ds/seg-beats/#ctsn-loves-segment-tree

    qes1.给一个序列,支持区间取min,然后询问区间max,区间和(HDU5306 Gorgeous Sequence)

    做法:维护区间最大值Max,次大致Se,区间和Sum以及最大值个数Cnt,现在考虑如何对区间取min

    ①如果Max≤t ,显然这个t是没有意义的,直接返回

    ②如果 Se < t  ≤ Max 那么这个t就能更新当前区间中的最大值。于是我们让区间和加上 Cnt (t-Max),然后更新 Max为t  ,并打一个标记

    ③如果t  ≤ Se,那么这时你发现你不知道有多少个数涉及到更新的问题。于是我们的策略就是,暴力递归向下操作。然后上传信息


    以上就是讲了并且听懂了的内容哈哈哈,下面放上没讲或者没听懂的问题,以后来补哈哈哈

    ·线段树分治

    qes1.动态图支持加边与删边操作,询问连通性,可以离线

    ·DFS序

    qes1.每个点有f个值,每个点的g值为子树的f值之和。支持修改f值,询问子树g值的和

    qes2.给你一颗树,边权可能是负数,要求查询u这个点到v这个子树里的最远点

    ·主席树

    qes1.二位数点,强制在线

    qes2.区间查询第K大

    qes3.求树上两点之间的第K大

    qes4.给你一序列a1,a2,...,an。给Q个询问,每次给出l,r,x求l,r之间与x异或之后最大的数

    ·CDQ分治

    qes1.三维数点

    qes2.一个图,对于所有i,j,k求出从i到j不经过k的最短路长度

  • 相关阅读:
    建立十字链表
    KMP算法
    魔术师发牌问题(循环链表)
    约瑟夫问题(循环链表)
    中缀表达式 转 (逆)波兰表达式
    中缀表达式求值
    迷宫问题(回溯法)
    范数
    AUC
    概率论
  • 原文地址:https://www.cnblogs.com/overrate-wsj/p/12198010.html
Copyright © 2011-2022 走看看