可持久化:可以保存历史版本
权值线段树:每一个叶子节点a[i]:表示 i 出现的次数
学习资料:前置技能:可持久化含义,权值线段树,可参考Menci博客
写法可参考bilibili中qsc算法讲堂
离散化:vector排序后erase,low_bound查找即可
模板
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e5+7;
int n,q,root[maxn],a[maxn],l,r,k,cnt;
vector<int>v;
struct node{
int l,r,sum;
}t[maxn*40];
int get_id(int x){
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int k){
t[++cnt]=t[y],t[cnt].sum++,x=cnt;
if(l==r) return;
int mid=(l+r)/2;
if(k<=mid) update(l,mid,t[x].l,t[y].l,k);
else update(mid+1,r,t[x].r,t[y].r,k);
}
int query(int l,int r,int x,int y,int k){
if(l==r) return l;
int mid=(l+r)/2;
int sum=t[t[y].l].sum-t[t[x].l].sum;
if(sum>=k) query(l,mid,t[x].l,t[y].l,k);
else query(mid+1,r,t[x].r,t[y].r,k-sum);
}
int main(){
while(scanf("%d%d",&n,&q)!=EOF){
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
v.push_back(a[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++){
update(1,n,root[i],root[i-1],get_id(a[i]));
}
while(q--){
scanf("%d%d%d",&l,&r,&k);
printf("%d\n", v[query(1,n,root[l-1],root[r],k)-1]);
}
}
}
kuangbin专题
A
分析
主席树板子题
B SPOJ COT
分析
根据dfs序建主席树,lca求最近公共祖先结点后,正常的按照主席树查询第k大即可
动态求区间第k大
分析
待补
HDU4348
分析
对每个t建立主席树,像线段树那样加lazy,主席树求和传递lazy即可