静态可持久化线段树(主席树)

题目背景

这是个非常经典的主席树入门题——静态区间第K小

数据已经过加强,请使用主席树。同时请注意常数优化

题目描述

如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。

输入输出格式

输入格式:

第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。

第二行包含N个正整数,表示这个序列各项的数字。

接下来M行每行包含三个整数 l, r, kl,r,k , 表示查询区间 [l, r][l,r] 内的第k小值。

输出格式:

输出包含k行,每行1个正整数,依次表示每一次查询的结果

题解及静态可持久化线段树总结

  对于求取第k大的问题我们通常运用的是权值线段树来解决,但是,单颗权值线段树只能求解在整个取件中第k大的数,而我们要求解的是区间中第k大的数,自然一颗权值线段树就不能解决了。那么,我们考虑如何用多颗权值线段树来维护一个区间的第k大呢?

  对于一个区间[l, r]的和我们可以把它看作两个区间[1, l - 1]的和与[1, r -1]的和作差,这说明和的运算满足“区间上的可加性”,但是区间中的第几大满不满足这种“区间上的可加性”呢?

  证明如下:

  对于一个数a[i]在区间[1, l -1]中有(k1 - 1)个数比他小(即他排在k1位),在区间[1, r]中有(k2 - 1)个数比他小(即他排在k2位),又因为l - 1 < r,所以在[1, l - 1]区间中的(k1 - 1)个数一定都存在于区间[1, r]中,那么剩余的(k2 - k1)个数一定都存在于[l, r]中,所以满足“区间上的可加性”,证毕。

  既然,区间第k大满足这种“区间可加性”,那么我们就可以开n颗权值线段树分别维护[1,1], [1,2],……,[1, n]的区间第k大,但是我们如果开n颗线段树的话空间是一定会炸掉的,所以,我们就要通过重复利用空间来使得整个所有的空间尽量的小。

  就像这样:(示例: 数列(4,1,3,2)查询(区间[1,3]中第2大)

  圈内中是这个数的sum(权值),圈外是结点下标。

  如果我们对于每一个插入的数都进行这样的操作的话就会形成这样的一幅图:

相关操作

  建树

  对于一颗主席树,我们要先一颗空树(所有的权值都为0)作为其他树的依靠,这就和普通的建立一颗线段树一样。

 void Build(pointer rt, int l, int r)
        {
            rt->l = l, rt->r = r;
            if(r - l == 0)
            {
                rt->sum = 0;
                return;
            }
            rt->lson = new Node(), rt->rson = new ()Node;
            Build(rt->lson, l , rt->mid()), Build(rt->rson, rt->mid() + 1, r);
            Pushup(rt);
        }

更新(加入其他的点)

  对于所有的新加入的点只改变这个点到根的路径,路径上,所以我们只要新开一个结点向下递归到叶子结点即可,然后再用点连起来。

 void Updata(pointer prert ,pointer rt, int l, int r, int x, int y)
        {
            rt->l = l, rt->r = r;
            if(r - l == 0)
            {
                rt->sum += y;
                return;
            }
            if(x <= rt->mid())
            {
                rt->lson = new Node();
                Updata(prert->lson, rt->lson, l, rt->mid(), x, y);
                rt->rson = prert->rson;
                Pushup(rt);
            }
            else
            {
                rt->rson = new Node();
                Updata(prert->rson, rt->rson, rt->mid() + 1, r, x, y);
                rt->lson= prert->lson;
                Pushup(rt);
            }
        }

 查询(同权值线段树)

int Query(pointer rtl, pointer rtr, int k)
        {
            if(rtl->r - rtl->l == 0)    return rtl->l;
            int d = rtr->lson->sum - rtl->lson->sum;
            if(d >= k)    return Query(rtl->lson, rtr->lson, k);
            else    return Query(rtl->rson, rtr->rson, k - d);
        }

代码

#include <bits/stdc++.h>
using namespace std;

const int MAX = 200005;

typedef struct Node{
    int l, r, sum;
    Node *lson, *rson;
    Node():l(0), r(0), sum(0), lson(NULL), rson(NULL){}
    int mid(){return (l + r) >> 1;}
    int len(){return r - l;}
}node, *pointer;

class Durable_Segement_Tree{
private:
    void Pushup(pointer rt)
        {
            rt->sum = rt->lson->sum + rt->rson->sum;
        }

public:
    pointer root[MAX];
    int a[MAX], num[MAX];

    void Build(pointer rt, int l, int r)
        {
            rt->l = l, rt->r = r;
            if(r - l == 0)
            {
                rt->sum = 0;
                return;
            }
            rt->lson = new Node(), rt->rson = new ()Node;
            Build(rt->lson, l , rt->mid()), Build(rt->rson, rt->mid() + 1, r);
            Pushup(rt);
        }

    void Updata(pointer prert ,pointer rt, int l, int r, int x, int y)
        {
            rt->l = l, rt->r = r;
            if(r - l == 0)
            {
                rt->sum += y;
                return;
            }
            if(x <= rt->mid())
            {
                rt->lson = new Node();
                Updata(prert->lson, rt->lson, l, rt->mid(), x, y);
                rt->rson = prert->rson;
                Pushup(rt);
            }
            else
            {
                rt->rson = new Node();
                Updata(prert->rson, rt->rson, rt->mid() + 1, r, x, y);
                rt->lson= prert->lson;
                Pushup(rt);
            }
        }

    int Query(pointer rtl, pointer rtr, int k)
        {
            if(rtl->r - rtl->l == 0)    return rtl->l;
            int d = rtr->lson->sum - rtl->lson->sum;
            if(d >= k)    return Query(rtl->lson, rtr->lson, k);
            else    return Query(rtl->rson, rtr->rson, k - d);
        }

};

struct VAL
{
    int val, pos;
}p[MAX];

int ans[MAX];
Durable_Segement_Tree tree;
bool comp1(const VAL & a, const VAL & b)    {return a.val < b.val;}
bool comp2(const VAL & a, const VAL & b)    {return a.pos < b.pos;}
int main()
{
//    freopen("3834.in", "r", stdin);
//    freopen("3834.out", "w", stdout);

    memset(tree.num, 0, sizeof(tree.num));
    int n, m, x, y, k;
    int cnt = 0;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++ i)
    {
        scanf("%d", &p[i].val);
        p[i].pos = i;
    }
    tree.root[0] = new Node();
    tree.Build(tree.root[0], 1, n);
    sort(p + 1, p + n+1, comp1);
    for(int i = 1; i <= n; ++ i)
        {
        //    if(p[i].val != p[i - 1].val)    tree.a[p[i].pos] = ++ cnt, ans[cnt] = p[i].val;
            tree.a[p[i].pos] = i;
            tree.num[p[i].pos] ++;
        }
//    sort(p + 1, p + n+1, comp2);
    for(int i = 1; i <= n; ++ i)
    {
        tree.root[i] = new Node();
        tree.Updata(tree.root[i - 1], tree.root[i], 1, n, tree.a[i], tree.num[i]);
    }
    for(int i = 1; i <= m; ++ i)
    {
        scanf("%d%d%d", &x, &y, &k);
        printf("%d\n", p[tree.Query(tree.root[x - 1], tree.root[y], k)].val);
    }
}

参考文献

http://www.cnblogs.com/zyf0163/p/4749042.html

  

原文地址:https://www.cnblogs.com/2020pengxiyue/p/9351556.html

时间: 2024-10-10 15:23:52

静态可持久化线段树(主席树)的相关文章

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

可持久化线段树--主席树

浅谈可持久化线段树--主席树 权值线段树 权值线段树和普通线段树不一样的地方就是在于 它的结点存储的是区间内数的个数 这个线段树的好处就在于我们可以根据 左子树 和 右子树 的大小从而进行 查找某个数的排名 或者 查找排名为rk的数 可持久化的含义 可持久数据结构主要指的是我们可以查询历史版本的情况并支持插入,利用使用之前历史版本的数据结构来减少对空间的消耗(能够对历史进行修改的是函数式). 主席树的建树过程: 最开始的时候就是一个空树 然后我们再插入一个元素3 再加入一个元素 1 模版一 :求

可持久化数据结构之主席树

转自:http://finaltheory.info/?p=249 HomeACM可持久化数据结构之主席树 06十2013 可持久化数据结构之主席树 Written by FinalTheory on. Posted in ACM 引言 首先引入CLJ论文中的定义: 所谓的“持久化数据结构”,就是保存这个数据结构的所有历史版本,同时利用它们之间的共用数据减少时间和空间的消耗. 本文主要讨论两种可持久化线段树的算法思想.具体实现以及编码技巧. 核心思想 可持久化线段树是利用函数式编程的思想,对记录

权值线段树&amp;&amp;可持久化线段树&amp;&amp;主席树

权值线段树 顾名思义,就是以权值为下标建立的线段树. 现在让我们来考虑考虑上面那句话的产生的三个小问题: 1. 如果说权值作为下标了,那这颗线段树里存什么呢? ----- 这颗线段树中, 记录每个值出现的次数 2.权值很大怎么办?数组空间不够啊 ----- 可以先离散化,再记录 3.那权值线段树到底是用来干嘛的呢? ----- 可以快速求出第k小值(其实主要还是为了主席树做铺垫啦) 那第k小值该怎么求呢??? 从树根依次往下 若当前值K大于左儿子的值,则将K-=左儿子的值,然后访问右儿子 若当前

小结:线段树 &amp; 主席树

概要: 就是用来维护区间信息,然后各种秀智商游戏. 应用: 优化dp.主席树等. 技巧及注意: size值的活用:主席树就是这样来的.支持区间加减,例题和模板:主席树,[BZOJ]1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树),[BZOJ]1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套可持久化线段树(主席树)) 01(就是更新和不更新等这种对立操作)情况:我们就要在各个更新的操作中明白

UOJ#218. 【UNR #1】火车管理 线段树 主席树

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html 题解 如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖.区间求和的线段树上完成这个问题. 于是本题的重点转到了如何求新的栈顶. 考虑用一个主席树维护一下每一个时刻每一个位置的栈顶元素的进栈时间,那么新的栈顶就是 当前位置栈顶的进栈时间-1 这时候的栈顶元素,然后这个东西也可以用我们维护的进栈时间来得到,所以我们只需要弄一个支持区间覆盖单点查询历史版本的主席树:这

4771: 七彩树 主席树

题意:给定一棵树  每个结点有一个颜色 然后又m个询问 询问:x d   问x的子树内不超过dep[x]+d 深度的子树结点一共有多少个颜色? 1.可以先将问题简化为问整个子树内有多少个不同的颜色  暴力解法树套树  但是可以用一个技巧来快速维护: 一个颜色一个颜色地处理  把所有相同颜色的点按照dfs序排序,每个点给自己的位置贡献1,相邻的两个点给lca贡献−1.然后只要区间内存在这种颜色,则其子树内的权值和必定为1.那么只需要这样子染好所有颜色之后询问子树和. 所以如果问题是这样的话只要一个

【BZOJ3439】Kpm的MC密码 trie树+主席树

Description 背景 想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的...),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身份验证问题了... 描述 Kpm当年设下的问题是这样的: 现在定义这么一个概念,如果字符串s是字符串c的一个后缀,那么我们称c是s的一个kpm串. 系统将随机生成n个由a…z组成的字符串,由1…n编号(s1,s2…,sn),然后将它们按序告诉你,接下来会给你n个数字,分别为k1…kn,对于每 一个k

bzoj 3545&amp;&amp;3551: [ONTAK2010]Peaks &amp;&amp;加强版 平衡树&amp;&amp;并查集合并树&amp;&amp;主席树

3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Status] Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. I