主席树入门野生动物园
有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域
都饲养着一头狮子。这些狮子从北到南编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强
。饲养员cmdButtons决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强的狮子
进行投喂。值得注意的是,cmdButtons不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此cmdButtons
的投喂区间是互不包含的。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。
Input
输入文件第一行有两个数N和M。此后一行有N个数,从南到北描述狮子的觅食能力值。此后M行,每行描述一次投喂
。第t+2的三个数I,J,K表示在第t次投喂中,cmdButtons选择了区间[I,J]内觅食能力值第K强的狮子进行投喂。
1<=N<=100000,1<=M<=50000
Output
有M行,每行一个整数。第i行的整数表示在第i次投喂中吃到食物的狮子的觅食能力值。
Sample Input
7 2
1 5 2 6 3 7 4
1 5 3
2 7 1
Sample Output
3
2
#include<bits/stdc++.h> #include<algorithm> #define N 100010 using namespace std; int sum[N*20],rt[N*20],ch[N*20][2],a[N],b[N],n,m,tot; void build(int &now,int l,int r) { now=++tot; sum[now]=0; if(l==r)return ; int mid=(l+r)>>1; build(ch[now][0],l,mid); build(ch[now][1],mid+1,r); } void update(int &now,int l,int r,int last,int p) //now结点的编号,l,r左右边界,last上一个树对应结点的编号(根对根,左对左,右对右) //p要加入的值 { now=++tot;//新开一个结点出来,并复制上一个树的左右结点 ch[now][0]=ch[last][0]; ch[now][1]=ch[last][1]; sum[now]=sum[last]+1; if(l==r)return ; int mid=(l+r)>>1; if(p<=mid) update(ch[now][0],l,mid,ch[last][0],p); else update(ch[now][1],mid+1,r,ch[last][1],p); } int query(int l,int r,int x,int y,int k) { if(l==r)return l; int mid=(l+r)>>1; int cnt=sum[ch[y][0]]-sum[ch[x][0]]; if(k<=cnt) return query(l,mid,ch[x][0],ch[y][0],k); else return query(mid+1,r,ch[x][1],ch[y][1],k-cnt); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i]; sort(b+1,b+n+1); int tt=unique(b+1,b+n+1)-b-1; for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+n+1,a[i])-b; build(rt[0],1,tt); for(int i=1;i<=n;i++) update(rt[i],1,tt,rt[i-1],a[i]); // for (int i=0;i<=n;i++) // cout<<i<<" "<<rt[i]<<endl; while(m--) { int x,y,k; scanf("%d%d%d",&x,&y,&k); printf("%d\n",b[query(1,tt,rt[x-1],rt[y],k)]); } } /* 7 2 1 5 2 6 3 7 4 1 5 3 2 7 1 rt[0]...1 rt[1]...14 rt[2]...18 rt[3]...22 rt[4]...26 rt[5]...30 rt[6]...34 rt[7]...37 */