[模板]主席树及其应用

可持久化权值线段树;

root数组记录第i版本根, 每次建树时只新建当前位相关子节点, 不相关子节点直接用上一版本的原节点

有前缀和及权值树性质, 可区间查询k小数


1.查询区间第k小

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
 
const int MAXN = 1e5 + 10;

struct prt
{
	struct node { int lson, rson, num;} T[MAXN * 40];
	int root[MAXN], cnt;
	prt() { cnt = 0; }
	
	void update(int l, int r, int &now, int pre, int a) //新建一支 
	{ 
	    now = ++cnt;
	    T[now] = T[pre];
	    T[now].num++;
	    if(l == r) return ;
	    int mid = (l + r) >> 1;
	    if(a <= mid) update(l, mid, T[now].lson, T[pre].lson, a);
	    else update(mid + 1, r, T[now].rson, T[pre].rson, a);
	}
	
	int query(int l, int r, int now, int pre, int k) //查询区间排名为K的映射元素值 
	{
	    if(l == r) return l;
	    int mid = (l + r) >> 1;
	    int lnum = T[T[now].lson].num - T[ T[pre].lson ].num;
	    if(k <= lnum) return query(l, mid,T[now].lson, T[pre].lson, k);
	    else return query(mid + 1, r, T[now].rson, T[pre].rson, k - lnum);
	}	
};
 
struct lsh
{
	int v[MAXN], vl; 
	lsh() { vl = 0; }
	void pb(int val) { v[vl++] = val; } //向后加元素 
	void init() { sort(v, v + vl); vl = unique(v, v + vl) - v; } //初始化排序,重置大小 
	int find(int val) { return lower_bound(v, v + vl, val) - v;} //查找元素下标
	int get(int pos) { return v[pos]; }  //通过下标返回元素 
};

int a[MAXN];
 
int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		int n, m;
 		scanf("%d%d", &n, &m);
	    lsh V;
	    prt T;
	    for(int i = 1; i <= n; i++)
	    {
	    	scanf("%d", &a[i]);
	    	V.pb(a[i]);
		}
	    
	    V.init();
	    
	    for(int i = 1; i <= n; i++)
	        T.update(0, n, T.root[i], T.root[i - 1], V.find(a[i]));
	    
	    int a, b, k;
	 	
	    for(int i = 1; i <= m; i++)
	    {
	        scanf("%d%d%d", &a, &b, &k);
	        printf("%d
", V.get( T.query(0, n, T.root[b], T.root[a - 1], k) ) );
	    }	
	}
    
 
    return 0;
}
原文地址:https://www.cnblogs.com/zeolim/p/12270362.html