可持久化线段树 1(主席树模板)

【模板】可持久化线段树 1(主席树)(luogu)

(本人的模板)

Description

题目背景

这是个非常经典的主席树入门题——静态区间第 kk 小数据已经过加强,请使用主席树。同时请注意常数优化

题目描述

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

输入格式

第一行包含两个正整数 n,mn,m,分别表示序列的长度和查询的个数。第二行包含 nn 个整数,表示这个序列各项的数字。接下来 mm 行每行包含三个整数 l, r, kl,r,k , 表示查询区间 [l, r][l,r] 内的第 kk 小值。

输出格式

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

Code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N=2e5+10;
struct node
{
    int lc,rc,sum;
}f[N*40];
struct mode
{
    int v,id;
    bool operator <(const mode &o)const
    {
        return v<o.v;
    }
}a[N];
int n,m,rt[N],d[N],l,r,k,tot,cnt,re[N];
void build(int l,int r,int &x,int y,int pos)
{
    x=++tot;
    f[x]=f[y],f[x].sum++;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(pos<=mid) build(l,mid,f[x].lc,f[y].lc,pos);
    else build(mid+1,r,f[x].rc,f[y].rc,pos);
}
int ans(int l,int r,int x,int y,int k)
{
    if(l>=r) return l;
    int cnt=f[f[x].lc].sum-f[f[y].lc].sum;
    int mid=(l+r)>>1;
    if(cnt>=k) return ans(l,mid,f[x].lc,f[y].lc,k);
    else return ans(mid+1,r,f[x].rc,f[y].rc,k-cnt);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i].v),a[i].id=i;
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
    {
        if(i==1 || a[i].v!=a[i-1].v) re[++cnt]=a[i].v;
        d[a[i].id]=cnt;
    }
    for(int i=1;i<=n;i++) build(1,n,rt[i],rt[i-1],d[i]);
    while(m--)
    {
        scanf("%d%d%d",&l,&r,&k);
        printf("%d\n",re[ans(1,n,rt[r],rt[l-1],k)]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/hsez-cyx/p/12267989.html

时间: 2024-10-13 16:36:29

可持久化线段树 1(主席树模板)的相关文章

[可持久化线段树(主席树)]

主席树 抛出问题 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示序列的长度和查询的个数. 第二行包含N个整数,表示这个序列各项的数字. 接下来M行每行包含三个整数l, r, kl,r,k , 表示查询区间[l, r][l,r]内的第k小值. 输出格式: 输出包含k行,每行1个整数,依次表示每一次查询的结果 解决问题 主席树(可持久化线段树)法 于是针对这个问题,新的数据结构诞生了,也就是主席树. 主席树本名

归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665

如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k大 ,,,, 这个问题的通用算法是 划分树,, 说白一点就是把快速排序的中间结果存起来, 举个栗子 原数列 4 1 8 2 6 9 5 3 7 sorted 1 2 3 4 5 6 7 8 9 ........................... qs[0] 4 1 8 2 6 9 5 3 7 q

luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iomanip> #include<algorithm> #include<ctime> #include<queue> #inc

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

题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示序列的长度和查询的个数. 第二行包含N个正整数,表示这个序列各项的数字. 接下来M行每行包含三个整数 l, r, kl,r,k , 表示查询区间 [l, r][l,r] 内的第k小值. 输出格式: 输出包含k行,每行1个正整数,依次表示每一次查

可持久化线段树(主席树)新手向教程

嗯今天来讲讲一个高端玩意,叫可持久化线段树. 新手向,有点耐心是一定可以懂的 知识储备 首先你得知道线段树是什么,不然也不需要学这个东西 线段树 引入 现在呢我们来思考一个问题,如果题目有需要保存线段树更改前的各个历史版本(比如给一个数列的前n项各建一棵线段树),我们应该怎么存? 每个版本存一棵树吗? 不不不太多了会爆空间的QAQ 事实上,如果要存储前我们只需要修改少量点就可以,因为每两个版本间有很多的重复部分. 解析 圈里面是这个区间包含的数字在数列里出现的次数. 比如:现在我们有数列 2 1

洛谷 [P3834] 可持久化线段树(主席树)

主席树可以存储线段树的历史状态,空间消耗很大,一般开45n即可 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <queue> #define lson l, mid #define rson mid+1, r #define ll long long using name

可持续化线段树(主席树)

什么是主席树 可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 因此可持久化线段树也叫函数式线段树又叫主席树. 可持久化数据结构 在算法执行的过程中,会发现在更新一个动态集合时,需要维护其过去的版本.这样的集合称为是可持久的. 实现持久集合的一种方法时每当该集合被修改时,就将其整个的复制下来,但是这种方法会降低执行速度并占用过多的空间. 考虑一个持久集合S. 如图所示,对集合的

【模板】【数据结构】【树】主席树

技巧一:离散去重 for(int i=1;i<=n;i++) scanf("%d",&a[i] ),b[i]=a[i]; sort(b+1,b+n+1); int nn=unique(b+1,b+n+1)-b-1;//假设有x个数,那么nn指针会停在第x+1个数的位置 ,nn及以后的都是重复的元素for(int i=1;i<=n;i++) id[i]=lower_bound(b+1,b+nn+1,a[i])-b;//离散过后的新value 技巧二:可持久化数据结构

神奇的树(主席树思想的应用)

主席树这个概念应该不陌生吧!恩?不会, 戳这里. 主席树(函数式线段树)用的是函数思想,一个节点开数组用来保存自己的左右节点,这样节省许多不必要的空间,还可以保存许多历史状态.而这里我们用的是主席树的函数思想来实现. 上题:http://acm.hdu.edu.cn/showproblem.php?pid=5444 题目大意: 给你一个序列,第一个数为二叉树根节点,之后每个数往上加节点,且保证左节点小于根节点,且保证右节点大于根节点.且每个节点最多有2个子节点.然后再查询位置,每往左找输出一个E

[SCOI2015]情报传递[树剖+主席树]

[SCOI2015]情报传递 题意大概就是 使得在 \(i\) 时刻加入一个情报员帮您传情报 然后询问 \(x,y,c\) 指 \(x\)到\(y\)多少个人有风险-(大于c)的都有风险-每天风险值+1 看起来-不太可做- 每次要整棵树+1复杂度也需要\(log^2\)的树套树吧 但是显然不用啊 查询的时候减掉就可以了- 所以直接树剖上面无脑主席树就可以了啊- #include <bits/stdc++.h> // #define int long long #define rep(a , b