• 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
    ",Hash[p]);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Hadoop学习:Map/Reduce初探与小Demo实现
    OCR OneNote
    百度OCR识别示例
    Sqlserver 中添加数据库登陆账号并授予数据库所有者权限
    IIs 中运行asp程序出现“An error occurred on the server when processing the URL. Please contact the system administrator.”错误
    SqlServer 删除重复记录
    Chrome 制作绿色便携版
    Asp.net 在网页编写C#代码示例-- 一个简单的web MsSql 命令执行环境
    C# 中如何将List<string>里的集合转换成字符串并按指定的字符进行分隔?
    使用SQL SERVER FOR XML PATH将多个结果集转换成一行并进行去重处理
  • 原文地址:https://www.cnblogs.com/shutdown113/p/9352970.html
Copyright © 2020-2023  润新知