• 算法数据结构学习笔记


    算法数据结构学习笔记

    1.主席树

    朴素做法,对于每一个版本都新建一个线段树,显然炸空间

    我们考虑修改之后只有修改的点到根节点被修改,我们可以新建这些节点,并与未修改的节点连接

    主席树模板:动态第k大

    前置知识:权值线段树查找第k大

    对于1~i建一个主席树,再通过其前缀性质相减,最后查询即可

    1.离散化

    STL大法好,sort,unique,lowerbound一套带走

    2.如何储存主席树

    const int maxn = 2e5+5;
    struct node
    {
    	int l,r,sum;
    }hjt[maxn*40];
    int cnt,root[maxn];
    

    由于我们需要存历史版本,所以不用初始建树

    插入函数

    void insert(int l,int r,int pre,int &p,int x)
    {
    	hjt[++cnt]=hjt[pre];
        p=cnt;
        hjt[now].sum++;
        if(l==r)
            return;
        int mid=(l+r)>>1;
        if(x<=mid)
            insert(l,mid,hjt[pre].l,hjt[p].l,x);
        else 
            insert(mid+1,r,hjt[pre].r,hjt[p].r,x);
    }
    

    询问第k大

    int query(int l,int r,int lp,int rp,int k)
    {
       	if(l==r)
            return l;
    	int tmp = hjt[hjt[rp].l].sum-hjt[hjt[lp].l].sum;
        if(k<=tmp)
            return query(l,mid,hjt[lp].l,hjt[rp].l,k);
        else 
            return query(mid+1,r,hjt[lp].r,hjt[rp].r,k-tmp);
    }
    

    2.可持久化数组

    模板题:LGP3919

    奇技淫巧:STL rope

    //rope
    #include<ext/rope>
    

    rope是个块状链表,支持O(1)复制

    正解:主席树

    1.用原数组建立一个普通线段树

    2.根据题意建立版本

    3.点分治

    例题:POJ 1741

    对于给定的一颗树,求两点距离不超过k的点对数量

    首先简化问题,路径经过一个点的两点距离不超过k的点对数量

    那么,就以该点作为根节点,预处理出所有点到根节点的距离,设为(dist[i])

    然后对其进行排序,再双指针扫一遍求出符合要求的点对数目

    但很显然,当两点的LCA不是所选的根节点时,不符合题意,我们需要容斥

    对于根节点的每一个子树,我们再把其所有dist进行排序,再求出加和大于k的即可。

    解决了这个之后,原问题就很好解决了,只需要把刚才那个根节点删除,并继续重复上述操作即可

    为了使得这个操作次数尽量少,我们每次选取的节点应为树的重心

    所以,整个算法的流程就是:

    1.找树的重心

    2.以该点为根结点,处理出所有dist

    3.排序,双指针计算和大于k的

    4.容斥,找子树中大于k的,计算答案

    5.重复1

  • 相关阅读:
    浅水方程
    Delaunay三角剖分算法
    计算机图形学知名期刊杂志(转载)
    Sql 主键自增
    Skinny triangle
    开源免费天气预报接口API以及全国所有地区代码!!
    Navier Stokes(纳维叶-斯托克斯)方程
    java.util.Date_与_java.sql.Date互转_及_字符串转换为日期时间格式
    2015最后一天
    html标签
  • 原文地址:https://www.cnblogs.com/Marcelo/p/14540340.html
Copyright © 2020-2023  润新知