poj2104(主席树)

K-th Number

题意:

  求出【l,r】区间第k大数。

分析:

  学的似懂非懂,我的理解是建立n个线段树,每个线段树保留之前版本的信息,通过节点的复用减少空间复杂度。因为我们发现当我们改变一个节点时,只有一条链上的节点的信息需要更新,所以我们每次新建一个线段树时,其实只要建立那条链上的节点个数的新节点,其他可以通过节点指向以前的节点。

  对于求第k大的树,可以每次把数据离散化后(数据就变成了1~n),然后依次对sum数组进行初始化,类似用线段树找逆序数一样,从l点对应的sum值开始累加,一直加到i点时,如果sum大于等于k,那么我们要找到的数就是Hash数组里第i大的数,即Hash【i】。

  学习资料:主席树视频讲解     大佬博客

代码:

#include <map>
#include <queue>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>

using namespace std;
#define ll long long
#define ull unsigned long long
#define cls(x) memset(x,0,sizeof(x))
#define clslow(x) memset(x,-1,sizeof(x))
#define lson l,m
#define rson m+1,r

const int maxn=1e5+100;
const int inf=0x3f3f3f3f;

int n,m,tot;

int a[maxn],Hash[maxn];
int L[maxn<<2],R[maxn<<2],T[maxn<<2],sum[maxn<<2];

int build(int l,int r)
{
    int rt=++tot;
    sum[rt]=0;
    if(l<r){
        int m=(l+r)>>1;
        L[rt]=build(lson);
        R[rt]=build(rson);
    }
    return rt;
}

int update(int pre,int l,int r,int x)
{
    int rt=++tot;
    L[rt]=L[pre];
    R[rt]=R[pre];
    sum[rt]=sum[pre]+1;
    if(l<r){
        int m=(l+r)>>1;
        if(x<=m)    L[rt]=update(L[pre],lson,x);
        else        R[rt]=update(R[pre],rson,x);
    }
    return rt;
}

int query(int u,int v,int l,int r,int k)
{
    if(l>=r)    return l;
    int m=(l+r)>>1;
    int num=sum[L[v]]-sum[L[u]];
    if(num>=k)  return query(L[u],L[v],lson,k);
    else        return query(R[u],R[v],rson,k-num);
}

int binarySearch(int key,int* a,int n)
{
    int l=1,r=n;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(a[mid]==key) return mid;
        else if(a[mid]<key) l=mid+1;
        else if(a[mid]>key) r=mid-1;
    }
    return -1;
}

int main()
{
//    freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        tot=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            Hash[i]=a[i];
        }

        sort(Hash+1,Hash+n+1);
        int d=1;
        for(int i=2;i<=n;i++){
            if(Hash[i]!=Hash[i-1])    Hash[++d]=Hash[i];
        }
        T[0]=build(1,d);
        for(int i=1;i<=n;i++){
            int x=binarySearch(a[i],Hash,d);
            T[i]=update(T[i-1],1,d,x);
        }

        for(int i=1;i<=m;i++){
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            int p=query(T[l-1],T[r],1,d,k);
            printf("%d\n",Hash[p]);
        }
    }
    return 0;
}
View Code

 

posted on 2018-07-23 09:12  我过了样例耶  阅读(130)  评论(0编辑  收藏  举报

导航