点名

【题目描述】

在 J 班的体育课上,同学们常常会迟到几分钟,但体育老师的点名却一直很准时。

老师只关心同学的身高,他会依次询问当前最高的身高,次高的身高,第三高的身高,

等等。在询问的过程中,会不时地有人插进队伍里。你需要回答老师每次的询问。

【输入格式】

第一行两个整数 n m,表示先后有 n 个人进队,老师询问了 m 次

第二行 n 个整数,第 i 个数 Ai 表示第 i 个进入队伍的同学的身高为 Ai

第三行 m 个整数,第 j 个数 Bj 表示老师在第 Bj 个同学进入队伍后有一次询问

【输出格式】

m 行,每行一个整数,依次表示老师每次询问的答案。数据保证合法

【样例输入】

7 4

9 7 2 8 14 1 8

1 2 6 6

【样例输出】

9

9

7

8

【样例解释】

(9){No.1 = 9}; (9 7){No.2 = 9}; (9 7 2 8 14 1){No.3 = 7; No.4 = 8}

【数据范围】

40%的数据保证 n ≤ 1000

100%的数据保证 1 ≤ m ≤ n ≤ 30000; 0 ≤ Ai < 232

//又是主席树模板啊,最喜欢这样的题了!
//换种写法 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define maxn 30010
#define maxm 1000010

using namespace std;
ll n,m,cnt,num,a[maxn],root[maxn],order[maxn];
struct node{
    ll lc,rc,sum;
}t[maxm*5];

ll Build(ll S,ll L,ll R)
{
    ll k=++cnt;
    t[k].sum=S;
    t[k].lc=L;t[k].rc=R;
    return k;
}

void insert(ll &root,ll pre,ll pos,ll l,ll r)
{
    root=Build(t[pre].sum+1,t[pre].lc,t[pre].rc);
    if(l==r)return;
    ll mid=(l+r)/2;
    if(pos<=mid)insert(t[root].lc,t[pre].lc,pos,l,mid);
    else insert(t[root].rc,t[pre].rc,pos,mid+1,r);
}

ll Query(ll L,ll R,ll pos,ll l,ll r)
{
    if(l==r)return l;
    ll sum=t[t[R].lc].sum-t[t[L].rc].sum;
    ll mid=(l+r)/2;
    if(sum>=pos)return Query(t[L].lc,t[R].lc,pos,l,mid);
    else return Query(t[L].rc,t[R].rc,pos-sum,mid+1,r);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        order[i]=a[i];
    }
    sort(order+1,order+n+1);
    num=unique(order+1,order+n+1)-order-1;
    for(int i=1;i<=n;i++)
    {
        ll pos=lower_bound(order+1,order+num+1,a[i])-order;
        insert(root[i],root[i-1],pos,1,num);
    }
    ll l,r,k;
    for(int i=1;i<=n;i++)
    {
        l=1;scanf("%lld",&r);k=i;
        ll p=Query(root[l-1],root[r],k,1,num);
        printf("%lld
",order[p]);
    }
    return 0;
} 
心若向阳,无言悲伤
折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
原文地址:https://www.cnblogs.com/L-Memory/p/6289712.html