【JZOJ1011】Zoo

problem

Description

JZ拥有一个很大的野生动物园。这个动物园坐落在一个狭长的山谷内,这个区域从南到北被划分成N个区域,每个区域都饲养着一头狮子。这些狮子从北到南编号为1,2,3,…,N。每头狮子都有一个觅食能力值Ai,Ai越小觅食能力越强。饲养员西西决定对狮子进行M次投喂,每次投喂都选择一个区间[I,J],从中选取觅食能力值第K强的狮子进行投喂。值得注意的是,西西不愿意对某些区域进行过多的投喂,他认为这样有悖公平。因此西西的投喂区间是互不包含的(即区间[1,10]不会与[3,4]或[5,10]同时存在,但可以与[9,11]或[10,20]一起)。同一区间也只会出现一次。你的任务就是算出每次投喂后,食物被哪头狮子吃掉了。

Input

觅食能力值。(1<=能力值<=maxlongint)。此后M行,每行描述一次投喂。第t+2的三个数I,J,K表示在第t次投喂中,西西选择了区间[I,J]内觅食能力值第K强的狮子进行投喂。

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

Data Constraint

Hint

对于100%的数据,有1<=N<=100000,1<=M<=50000。


analysis

  • 静态求区间第 k 小,经典的主席树

  • 首先离散化,把 n 个数搞到 [ 1 , n ] 中去

  • 然后一个点一个点插入操作,每次 O ( l o g 2 n ) ,共 O ( n l o g 2 n ) 时间

  • 这时求 [ x , y ] 区间的第 z 小,就可以拿 t r e e y t r e e x 1 去查找

  • 查找就是 O ( l o g 2 n ) 的树上二分而已,有点像 s p l a y 的查找

  • 然后就没了


code

#include<stdio.h>
#include<algorithm>
#define MAXN 100005

using namespace std;

int sum[MAXN*20],lson[MAXN*20],rson[MAXN*20];
int a[MAXN],b[MAXN],root[MAXN];
int n,m,tot;

int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0' || '9'<ch)
    {
        if (ch=='-')f=-1;
        ch=getchar();   
    }
    while ('0'<=ch && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

void maketree(int &t,int l,int r)
{
    t=++tot;
    if (l==r)return;
    int mid=(l+r)/2;
    maketree(lson[t],l,mid);
    maketree(rson[t],mid+1,r);
}

void update(int old,int &t,int l,int r,int x)
{
    t=++tot;
    lson[t]=lson[old],rson[t]=rson[old],sum[t]=sum[old];
    if (l==r)
    {
        sum[t]++;
        return;
    }
    int mid=(l+r)/2;
    if (x<=mid)update(lson[old],lson[t],l,mid,x);
    else update(rson[old],rson[t],mid+1,r,x);
    sum[t]=sum[lson[t]]+sum[rson[t]];
}

int query(int s,int t,int l,int r,int k)
{
    if (l==r)return l;
    int mid=(l+r)/2,cnt=sum[lson[t]]-sum[lson[s]];
    if (k<=cnt)return query(lson[s],lson[t],l,mid,k);
    return query(rson[s],rson[t],mid+1,r,k-cnt);
}

int main()
{
    //freopen("readin.txt","r",stdin);
    n=read(),m=read(); 
    for (int i=1;i<=n;i++)a[i]=b[i]=read();
    sort(b+1,b+n+1);
    int size=unique(b+1,b+n+1)-b-1;
    maketree(root[0],1,size);
    for (int i=1;i<=n;i++)
    {
        a[i]=lower_bound(b+1,b+1+size,a[i])-b;
        update(root[i-1],root[i],1,size,a[i]);
    }
    while (m--)
    {
        int x=read(),y=read(),z=read();
        printf("%d\n",b[query(root[x-1],root[y],1,size,z)]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/enjoy_pascal/article/details/80739741
zoo