野生动物园

来源:互联网 发布:工业数据采集 解决方案 编辑:程序博客网 时间:2024/04/29 13:23

Problem A:野生动物园

Time Limit:30000MS  Memory Limit:65536K
Total Submit:33 Accepted:16

Description

有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成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强的狮子进行投喂。 

Output

有M行,每行一个整数。第i行的整数表示在第i次投喂中吃到食物的狮子的觅食能力值。 

Sample Input

7 21 5 2 6 3 7 41 5 32 7 1

Sample Output

32数据范围:对于50%的数据,有1<=N<=10000,1<=M<=500;对于100%的数据,有1<=N<=100000,1<=M<=50000。

[Submit]   [Go Back]   [Status]   [Clarify]


线段树,

构建N个线段树,维护 其使第i个线段树表示加元素,从1加到i时,a[i]在每条线段[l,r]中为第几大,

这样可以快速求得区间第k大


由于范围较大,可以使用可持久化数据结构,不必完整的构建N个线段树,中间未更新的节点不必重新建造


#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;struct node{    int l,r,len;}t[5000010];int n,m,N;int a[100010],b[100010],root[100010];int build (int l,int r){    int i=++N;    if (l!=r)    {        int mid=(l+r)>>1;        t[i].l=build( l ,mid );        t[i].r=build( mid+1,r);    }    return i;}int change(int i, int l, int r ,int k ){    ++N; t[N]=t[i]; i=N;    t[i].len++;    if (l!=r)    {        int mid=(l+r)>>1;        if (k<=mid) t[i].l=change(t[i].l, l, mid, k);        else            t[i].r=change(t[i].r, mid+1, r, k);    }    return i;}int query(int i1,int i2,int l,int r ,int k){    if (l==r) return l;    else    {        int mid=(l+r) >>1;        if ( k<= t[ t[i1].l].len - t[ t[i2].l].len ) return query( t[i1].l, t[i2].l, l, mid, k);        else            return query( t[i1].r, t[i2].r, mid+1, r, k-( t[ t[i1].l ].len- t[t[i2].l].len ) );    }}int main(){    scanf("%d%d",&n,&m);    for (int i=1; i<=n; i++)        scanf("%d",&a[i]);    memcpy(b,a,sizeof(a));    sort(b+1,b+1+n);    N=1;    for (int i=2; i<=n; i++)        if (b[i]!=b[i-1] )  b[++N]=b[i];    root[0]=build(1,n);    for (int i=1; i<=n; i++)        root[i]=change(root[i-1],1,n,upper_bound(b+1,b+1+n,a[i])-(b+1) );    for (int i=1; i<=m; i++)    {        int x,y,k;        scanf("%d%d%d",&x,&y,&k);        printf("%d\n",b[ query( root[y],root[x-1] ,1, n, k ) ] );    }    return 0;}


0 0