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

https://www.luogu.org/problemnew/show/P3834

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;
const int maxn = 2e5 + 10;

#define RR freopen("gg.in", "r", stdin)

int n, m;
int cnt;

struct node {
    int L, R;//分别指向左右子树
    int sum;//该节点对应区间数的个数
    node() {
        sum = 0;
    }
} Tree[maxn * 20];

struct value {
    int x;//值的大小
    int id;//离散之前在原数组中的位置
} Value[maxn];

bool cmp(value v1, value v2) {
    return v1.x < v2.x;
}

int root[maxn];//多颗线段树的根节点
int rank[maxn];//原数组离散之后的数组

void init() {
    cnt = 1;
    root[0] = 0;
    Tree[0].L = Tree[0].R = Tree[0].sum = 0;
}

void update(int num, int &rt, int l, int r) {
    Tree[cnt++] = Tree[rt];//bu存在Tree[0]
    rt = cnt - 1;
    Tree[rt].sum++;
    if(l == r) return;
    int mid = (l + r)>>1;
    if(num <= mid) update(num, Tree[rt].L, l, mid);
    else update(num, Tree[rt].R, mid + 1, r);
}

int query(int i, int j, int k, int l, int r) {
    int d = Tree[Tree[j].L].sum - Tree[Tree[i].L].sum;
    if(l == r) return l;
    int mid = (l + r)>>1;
    if(k <= d) return query(Tree[i].L, Tree[j].L, k, l, mid);
    else return query(Tree[i].R, Tree[j].R, k - d, mid + 1, r);
}

int main() {
    RR;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &Value[i].x);
        Value[i].id = i;
    }
    //进行离散化
    sort(Value + 1, Value + n + 1, cmp);
    for(int i = 1; i <= n; i++) rank[Value[i].id] = i;
    init();
    for(int i = 1; i <= n; i++) {
        root[i] = root[i - 1];
    //    cout << root[i] << endl;
        update(rank[i], root[i], 1, n);//update(第i个数的排名,)
    }
    int left, right, k;
    for(int i = 1; i <= m; i++) {
        scanf("%d%d%d", &left, &right, &k);
        printf("%d\n", Value[query(root[left - 1], root[right], k, 1, n)].x);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/shandongs1/p/8454003.html

时间: 2024-07-30 22:30:16

[Luogu] 可持久化线段树 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

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

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

[Luogu 3701] 「伪模板」主席树

[Luogu 3701] 「伪模板」主席树 <题目链接> 这是一道网络流,不是主席树,不是什么数据结构,而是网络流. 题目背景及描述都非常的暴力,以至于 Capella 在做此题的过程中不禁感到生命流逝. S 向 byx 的树中的每一个人连有向边,手气君的树中的每一个人向 T 连有向边,边权为这个人的寿命.统计同一棵树中的膜法师数量 x.如果一个人是主席,那么边权要加上 x.(续得好啊) 然后,如果 byx 树中的一个点 i 能赢手气君树中的点 j,那么连 i->j,边权为 1. 跑最大

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. 如图所示,对集合的

Luogu Dynamic Ranking (带修改的主席树)

带修改的主席树: 原本的主席树是维护了一个线段树前缀. 那么前缀有没有想到什么东西? 树状数组\(Bits\)是不是很 ...... ? 那么现在,我们用树状数组套主席树,不就可以实现带修改的可持久化了吗. 具体来说 \(T[1]维护rt[1]\) , \(T[2]维护rt[1].rt[2]\) , \(T[3]维护rt[3]\) ...... 就与树状数组是一样的. 那么现在,两个具体的操作: 修改: 修改需要修改\(logN\)棵主席树,将涉及修改节点的\(log\)个主席树先删后加点即可.

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

技巧一:离散去重 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 技巧二:可持久化数据结构