主席树入门野生动物园
有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成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
*/

浙公网安备 33010602011771号