傳送門:http://acm.hdu.edu.cn/showproblem.php?pid=2665
主席樹呢,就是可持久化線段樹,非常神奇。我在B站看了qsc大神的視頻之後就大概懂意思了,先做個入門題,再慢慢學。
打個廣告:http://www.bilibili.com/video/av4619406/
題意是求區間內第k大的數(實際上是k小),主席樹是這樣做的,把n個數離散化之後建一個線段樹,每個葉子節點表示第x大的數分別有幾個,然後pushup上來這個區間內的數字總數。在這個線段樹中如果要求第k大的數很容易,就是找k在左區間還是右區間,在左區間的話,就是繼續找k。在右區間的話,就是k-左區間總數。找到葉子節點之後,這個下標就是第k個數的離散化後的下標。那麼我們對每個前綴建一個線段樹,就是通過主席樹來實現。然後在[l,r]區間求k的話,第r個線段樹-第l-1個線段樹,就是這個區間內的線段樹,然後用上面的思路來找第k個數就可以了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <ctime>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF=1e9+7;
const int maxn=100000;
int n,m,tot;
int a[maxn+10],rt[maxn+10];
struct node{
int l,r,sum;
}tree[maxn*20];
vector<int> v;
inline int getid(int x){
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void build(int l,int r,int &x){
x=++tot;
tree[x].sum=0;
if(l==r)return;
int m=(l+r)>>1;
build(l,m,tree[x].l);
build(m+1,r,tree[x].r);
}
void update(int l,int r,int &x,int y,int k){
x=++tot;tree[x]=tree[y];tree[x].sum++;
if(l==r){
return;
}
int m=(l+r)>>1;
if(k<=m)update(l,m,tree[x].l,tree[y].l,k);
else update(m+1,r,tree[x].r,tree[y].r,k);
}
int query(int l,int r,int x,int y,int k){
if(l==r)return l;
int m=(l+r)>>1;
int sum=tree[tree[y].l].sum-tree[tree[x].l].sum;
if(k<=sum)return query(l,m,tree[x].l,tree[y].l,k);
else return query(m+1,r,tree[x].r,tree[y].r,k-sum);
}
int main(){
//freopen("D://input.txt","r",stdin);
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
v.clear();
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
v.pb(a[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int cnt=v.size();
tot=0;build(1,cnt,rt[0]);
for(int i=1;i<=n;i++){
update(1,cnt,rt[i],rt[i-1],getid(a[i]));
}
while(m--){
int l,r,x;scanf("%d%d%d",&l,&r,&x);
printf("%d\n",v[query(1,cnt,rt[l-1],rt[r],x)-1]);
}
}
return 0;
}