【主席树】【模板】【Luogu P3834】可持久化线段树2

链接

Luogu P3834

题目描述

如题,给定 n 个整数构成的序列 a,将对于指定的闭区间 [l, r] 查询其区间内的第 k 小值。

思路

区间[l,r]表示在序号为l~r之中暂时存下了多少个数
那么我们就可以枚举序列a,每枚举到一个数就存为一个版本
l < r l<r l<r
T[r] - T[l-1]就可以得到区间l~r之中存入的数的信息
可以比较两个版本的左儿子,这样子就可以确定第k大数的这个k在左儿子还是右儿子

代码

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

using namespace std;

struct trr
{
    
    
	int k, ls, rs;	
}tr[32000005];

int cnt, n, m;
int p[1000005], a[1000005], T[1000005];

void add(int &x, int last)
{
    
    
	x = ++cnt;
	tr[x] = tr[last];
}

void build(int &x, int l, int r)
{
    
    
	x = ++cnt;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(tr[x].ls, l, mid);
	build(tr[x].rs, mid + 1, r);
}

void init(int &x, int last, int l, int r, int val)
{
    
                                                 
	add(x, last);                                
	if(l == r) {
    
                                     
		tr[x].k++;                                  
		return;                                     
	}                                            
	int mid = (l + r) >> 1;                      
	if(val <= mid) init(tr[x].ls, tr[last].ls, l, mid, val);
	if(val > mid) init(tr[x].rs, tr[last].rs, mid + 1, r, val);
	tr[x].k = tr[tr[x].ls].k + tr[tr[x].rs].k;
}

int ask(int u, int v, int l, int r, int go)
{
    
    
	int mid = (l + r) >> 1;
	int x = tr[tr[v].ls].k - tr[tr[u].ls].k;//计算出左儿子的版本差值
	if(l >= r) return l;
	if(x >= go) return ask(tr[u].ls, tr[v].ls, l, mid, go);//在左儿子
	if(go > x) return ask(tr[u].rs, tr[v].rs, mid + 1, r, go - x);//在右儿子,并且要把左儿子的大小去掉
}

int main()
{
    
    
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; ++i)
		scanf("%d", &a[i]), p[i] = a[i];
	sort(p + 1, p + n + 1);
	int q = unique(p + 1, p + n + 1) - p - 1;//离散化
	build(T[0], 1, q);//建一棵空树以便于转移版本
	for(int i = 1; i <= n; ++i) {
    
    
		int xx = lower_bound(p + 1, p + q + 1, a[i]) - p;//二分得到序号
		init(T[i], T[i - 1], 1, q, xx);
	}
	for(int i = 1; i <= m; ++i)
	{
    
    
		int l, r, k;
		scanf("%d%d%d", &l, &r, &k);
		printf("%d\n", p[ask(T[l - 1], T[r], 1, q, k)]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/LTH060226/article/details/119680675