主席树,就是n个线段树,用nlonn的空间实现
首先建立第一个线段树
把要查询的值离散化,建立值的线段树
每一次加入一个点
显然每一次只会修改logn个点
把其他的点直接建边连接即可
代码:
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=100005; int rt[N],a[N],n,m,b[N],x,cnt=1,now,y,k; struct Tree { int num,l,r,ls,rs; }T[80*N]; int ef(int x) { int l=1,r=cnt; while (l<r) { int mid=(l+r)/2; if (b[mid]<x)l=mid+1; else r=mid; } return l; } int build(int l,int r) { now++; if (l==r) { T[now].l=l; T[now].r=r; return now; } int k=now; T[k].l=l;T[k].r=r; int mid=(l+r)/2; if (l<=mid)T[k].ls=build(l,mid); if (mid<r)T[k].rs=build(mid+1,r); return k; } int insert(int x,int l,int r,int s) { now++; if (l==r) { T[now].l=l; T[now].r=r; T[now].num=T[x].num+1; return now; } int k=now,mid=(l+r)/2; T[k].l=l;T[k].r=r; if (s<=mid) { T[k].ls=insert(T[x].ls,l,mid,s); T[k].rs=T[x].rs; } else { T[k].ls=T[x].ls; T[k].rs=insert(T[x].rs,mid+1,r,s); } T[k].num=T[T[k].ls].num+T[T[k].rs].num; return k; } int find(int x,int y,int z) { if (T[x].l==T[x].r)return T[x].l; if (T[T[x].ls].num-T[T[y].ls].num>=z)return find(T[x].ls,T[y].ls,z); else return find(T[x].rs,T[y].rs,z-T[T[x].ls].num+T[T[y].ls].num); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++)scanf("%d",&a[i]); for (int i=1;i<=n;i++)b[i]=a[i]; sort(b+1,b+n+1); for (int i=2;i<=n;i++) if (b[i]!=b[i-1]) b[++cnt]=b[i]; rt[0]=1;build(1,n); for (int i=1;i<=n;i++)rt[i]=now+1,insert(rt[i-1],1,n,ef(a[i])); while (m--) { scanf("%d%d%d",&x,&y,&k); swap(x,y); printf("%d ",b[find(rt[x],rt[y-1],k)]); } return 0; }