模板
P3834 【模板】可持久化线段树 2(主席树) 区间求第 \(k\) 大
模板代码
#include<bits/stdc++.h>
using namespace std;
#define Maxn 200005
typedef long long ll;
inline int rd()
{
int x=0;
char ch,t=0;
while(!isdigit(ch = getchar())) t|=ch=='-';
while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
return x=t?-x:x;
}
/*
len: 数组长度
cnt: 数据范围
*/
int len,n,m,used;
int root[Maxn],a[Maxn],True_val[Maxn];
struct Li
{
int val,num;
}LI[Maxn];
bool cmp(Li x,Li y) { return x.val<y.val; }
struct Tree
{
int ls,rs,sum;
}tree[Maxn<<5];
void pushup(int p)
{
tree[p].sum=tree[tree[p].ls].sum+tree[tree[p].rs].sum;
}
void build(int p,int nl,int nr)
{
if(nl==nr) return;
int mid=(nl+nr)>>1;
if(mid>=nl) tree[p].ls=++used,build(tree[p].ls,nl,mid);
if(mid<nr) tree[p].rs=++used,build(tree[p].rs,mid+1,nr);
}
void add(int p1,int p2,int nl,int nr,int pos,int k)
{
if(nl==nr) { tree[p2].sum=tree[p1].sum+k; return; }
int mid=(nl+nr)>>1;
tree[p2]=tree[p1];
if(pos<=mid) tree[p2].ls=++used,add(tree[p1].ls,tree[p2].ls,nl,mid,pos,k);
else tree[p2].rs=++used,add(tree[p1].rs,tree[p2].rs,mid+1,nr,pos,k);
pushup(p2);
}
int query(int p1,int p2,int nl,int nr,int rank)
{
if(nl==nr) return nl;
int sumls=tree[tree[p2].ls].sum-tree[tree[p1].ls].sum,mid=(nl+nr)>>1;
if(rank<=sumls) return query(tree[p1].ls,tree[p2].ls,nl,mid,rank);
else return query(tree[p1].rs,tree[p2].rs,mid+1,nr,rank-sumls);
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
len=rd(),m=rd();
for(int i=1;i<=len;i++) LI[i].val=rd(),LI[i].num=i;
sort(LI+1,LI+len+1,cmp),LI[0].val=-1;
for(int i=1;i<=len;i++)
{
if(LI[i].val!=LI[i-1].val) n++;
a[LI[i].num]=n;
True_val[n]=LI[i].val;
}
for(int i=0;i<=len;i++) root[i]=++used;
build(root[0],1,n);
for(int i=1;i<=len;i++) add(root[i-1],root[i],1,n,a[i],1);
for(int i=1,l,r,k;i<=m;i++)
{
l=rd(),r=rd(),k=rd();
printf("%d\n",True_val[query(root[l-1],root[r],1,n,k)]);
}
//fclose(stdin);
//fclose(stdout);
return 0;
}
例题
P3899 [湖南集训]更为厉害
主要实现内容:给定一棵树,每次询问求出 \(u\) 的子树内,与 \(u\) 距离不超过 \(k\) 的所有节点的点权之和。
可以考虑以 \(dfn\) 序列作为 \(root[]\) ,每一个节点开一棵主席树。
修改时以每个点的深度为下标,附上点权。
这样就可以快速查询一颗子树(一段区间),并查询制指定深度的点权之和。