poj 2104 K-th Number

题目链接:点这里

Description

You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
That is, given an array a[1...n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: "What would be the k-th number in a[i...j] segment, if this segment was sorted?"
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2...5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.

Input

The first line of the input file contains n --- the size of the array, and m --- the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).
The second line contains n different integer numbers not exceeding 109 by their absolute values --- the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).

Output

For each question output the answer to it --- the k-th number in sorted a[i...j] segment.

Sample Input

7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3

Sample Output

5
6
3

【题意】

给你一个序列,然后不断的询问你,某个子区间里面的第K大的数。

【分析】

静态第k大,算是我做的第一个主席树的第一个裸题了,顺带花了两天看懂了主席树这个神奇的操作,确实很神奇,现在认识还是太浅,如果什么时候彻底懂了再来更新。看网上说还可以用划分树做,同样是不懂,有时间再去学。

【代码】

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<sstream>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS_1(a) memset(a,-1,sizeof(a))
#define MSinf(a) memset(a,0x3f,sizeof(a))
#define sin1(a) scanf("%d",&(a))
#define sin2(a,b) scanf("%d%d",&(a),&(b))
#define sll1(a) scanf("%lld",&(a))
#define sll2(a,b) scanf("%lld%lld",&(a),&(b))
#define sdo1(a) scanf("%lf",&(a))
#define sdo2(a,b) scanf("%lf%lf",&(a),&(b))
#define inf 0x3f3f3f3f
//#define lson i<<1,l,mid
//#define rson ((i<<1)|1),mid+1,r
#define uint unsigned int
typedef pair<int,int> PII;
#define A first
#define B second
#define pb push_back
#define MK make_pair
#define ll long long
template<typename T>
void read1(T &m) {
    T x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') {
        x=x*10+ch-'0';
        ch=getchar();
    }
    m = x*f;
}
template<typename T>
void read2(T &a,T &b) {
    read1(a);
    read1(b);
}
template<typename T>
void read3(T &a,T &b,T &c) {
    read1(a);
    read1(b);
    read1(c);
}
template<typename T>
void out(T a) {
    if(a>9) out(a/10);
    putchar(a%10+'0');
}
template<typename T>
void outn(T a) {
    if(a>9) out(a/10);
    putchar(a%10+'0');
    puts("");
}
using namespace std;
///-------------------------------------------------------------------
const int maxm=1e5+10;
const int M = maxm*30;
int n,q,m,tot;
int a[maxm],t[maxm];
int T[M],lson[M],rson[M],c[M];
void Init_hash(void)
{
    rep1(i,1,n) t[i]=a[i];
    sort(t+1,t+1+n);
    m=unique(t+1,t+1+n)-t-1;
}
int hash(int x)
{
    return lower_bound(t+1,t+m+1,x)-t;
}
int build(int l,int r)
{
    int root  = tot++;
    c[root] = 0;
    if(l!=r)
    {
        int mid = (l+r)>>1;
        lson[root] = build(l,mid);
        rson[root] = build(mid+1,r);
    }///lson和rson里面存的都是下标,也就是具体各个\
        儿子对应的位置,实际上的数据并不是存在了这里\
        说明了一些相互关系,相当于是一个个指针,\
        指向对应的数据,这就导致了最后生成的树的特点是\
        parent的位置*2不是儿子的下标,所以只能通过记录位置\
        来进行访问。
    return root;
}
int update(int root,int pos,int val)
{
    int newroot = tot++;
    int tmp = newroot;
    c[newroot] = c[root] + val;
    int l=1,r=m;
    while(l<r)
    {///这种地方还可以不用递归的方法实现,学到了
        int mid = (l+r)>>1;
        if(pos<=mid)
        {
            lson[newroot] = tot++;
            rson[newroot] = rson[root];
            newroot=lson[newroot];
            root = lson[root];
            r=mid;
        }
        else
        {
            rson[newroot] = tot++;
            lson[newroot] = lson[root];
            newroot =rson[newroot];
            root = rson[root];
            l=mid+1;
        }
        c[newroot]=c[root] + val;
    }
    return tmp;
}
int query(int left_root,int right_root,int k)
{
    int l=1,r=m;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(c[lson[left_root]]-c[lson[right_root]]>=k)
        {
            r=mid;
            left_root = lson[left_root];
            right_root = lson[right_root];
        }
        else
        {
            l=mid+1;
            k-=c[lson[left_root]]-c[lson[right_root]];
            left_root = rson[left_root];
            right_root = rson[right_root];
        }
    }
    return l;
}
int main() {
//    freopen("in.txt","r",stdin);
    while(sin2(n,q)!=EOF)
    {
        tot=0;
        rep1(i,1,n) read1(a[i]);
        Init_hash();
        T[n+1] = build(1,m);
        rep_0(i,n,0)
        {
            int pos = hash(a[i]);
            T[i]=update(T[i+1],pos,1);
        }
        while(q--)
        {
            int l,r,k;
            read3(l,r,k);
            printf("%d\n",t[query(T[l],T[r+1],k)]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zuhiul

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值