P3834 【模板】可持久化线段树 1(主席树)
题目描述
如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。
输入格式:
第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。
第二行包含N个整数,表示这个序列各项的数字。
接下来M行每行包含三个整数l,r,k l, r, kl,r,k , 表示查询区间[l,r][l, r][l,r]内的第k小值。
输出格式:
输出包含k行,每行1个整数,依次表示每一次查询的结果
输入输出样例
输入样例#1:
5 5
25957 6405 15770 26287 26465
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
输出样例#1:
6405
15770
26287
25957
26287
数据范围:
(1 leq N, M leq 2cdot 10^5)
对于数列中的所有数(a_i),均满足(-{10}^9 leq a_i leq {10}^9)
题解:
复习模板题,顺便写个博客吧,封装成立一个类。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200050
int n,m,a[N],kth[N],rt[N];
template<typename T>void read(T&x)
{
ll k=0; char c=getchar();
x=0;
while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
if (c==EOF)exit(0);
while(isdigit(c))x=x*10+c-'0',c=getchar();
x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
struct PrimeTree
{
struct Tree{int l,r,ls,rs,sum;}tr[N*22];
int num;
void bt(int &x,int l,int r)
{
x=++num;
tr[x].l=l; tr[x].r=r; tr[x].sum=0;
if (l==r)return;
int mid=(l+r)>>1;
bt(tr[x].ls,l,mid);
bt(tr[x].rs,mid+1,r);
}
void add(int &x,int last,int p)
{
x=++num;
tr[x]=tr[last];
tr[x].sum++;
if (tr[x].l==tr[x].r)return;
int mid=(tr[x].l+tr[x].r)>>1;
if (p<=mid)add(tr[x].ls,tr[last].ls,p);
else add(tr[x].rs,tr[last].rs,p);
}
int ask(int x,int y,int k)
{
if (tr[x].l==tr[x].r)return tr[x].l;
int lsum=tr[tr[y].ls].sum-tr[tr[x].ls].sum;
if (lsum>=k)return ask(tr[x].ls,tr[y].ls,k);
else return ask(tr[x].rs,tr[y].rs,k-lsum);
}
void init()
{
num=0;
bt(rt[0],1,n);
for(int i=1;i<=n;i++)add(rt[i],rt[i-1],a[i]);
}
}A;
int main()
{
#ifndef ONLINE_JUDGE
freopen("aa.in","r",stdin);
#endif
read(n); read(m);
for(int i=1;i<=n;i++)read(a[i]),kth[i]=a[i];
sort(kth+1,kth+n+1);
int num=unique(kth+1,kth+n+1)-kth-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(kth+1,kth+num+1,a[i])-kth;
A.init();
for(int i=1;i<=m;i++)
{
int x,y,k;
read(x); read(y); read(k);
printf("%d
",kth[A.ask(rt[x-1],rt[y],k)]);
}
}