zoukankan      html  css  js  c++  java
  • 【转】pku 2104 Kth Number 求某区间第k小数 归并排序+线段树

    学习了网上最常用的解法——归并树。
    所谓的归并树并不是什么新奇的东西,顾名思义,其实就是归并排序+线段树。把归并排序过程中的各区间排序后的结果,用线段树储存起来!
    对题目给定的区间,只要在线段树中查找组成该区间的各个子区间即可!——logN
    关键在于求出某个值在线段树各个子区间中,小于该值的元素个数,还是用到了二分,继续是logN。
    由于要求的是该区间的第k小元素,可以对整个排序完的数组进行二分查找,当某元素在该区间中排第k小,并且该元素属于该区间,即为答案。对排序数组进行二分查找,也是logN。
    耗时:2500ms+

    #include<stdio.h>
    #define N 100010
    struct T
    {
    int l,r,mid;
    }t[N*4];
    int sort[20][N];
    int id[20][N];
    int key[N],s,e;
    int build(int p,int l,int r,int dep)
    {
    t[p].l=l;
    t[p].r=r;
    t[p].mid=(l+r)>>1;
    if(l==r)
    {
    sort[dep][l]=key[l];
    id[dep][l]=l;
    return 0;
    }
    build(p<<1,l,t[p].mid,dep+1);
    build((p<<1)+1,t[p].mid+1,r,dep+1);
    int i,j,mid,now;
    mid=t[p].mid;
    i=l; j=mid+1; now=l;
    while(i<=mid && j<=r)
    {
    if(sort[dep+1][i]<sort[dep+1][j])
    {
    id[dep][now]=id[dep+1][i];
    sort[dep][now++]=sort[dep+1][i++];
    }
    else
    {
    id[dep][now]=id[dep+1][j];
    sort[dep][now++]=sort[dep+1][j++];
    }
    }
    if(i==mid+1)
    while(j<=r)
    {
    id[dep][now]=id[dep+1][j];
    sort[dep][now++]=sort[dep+1][j++];
    }
    else
    while(i<=mid)
    {
    id[dep][now]=id[dep+1][i];
    sort[dep][now++]=sort[dep+1][i++];
    }
    return 0;
    }
    int b_search(int left,int right,int v,int dep)
    {
    int l,r,m;
    l=left;r=right;
    if(v<=sort[dep][l])
    return 0;
    else if(v>sort[dep][r])
    return (r-l+1);
    while(l<r)
    {
    m=(l+r)>>1;
    if(sort[dep][m]>=v && sort[dep][m-1]<v)
    return m-left;
    if(sort[dep][m]<v)
    l=m+1;
    else
    r=m;
    }
    return l-left;
    }
    int query(int p,int v,int dep)
    {
    if(s<=t[p].l && t[p].r<=e)
    {
    return b_search(t[p].l,t[p].r,v,dep);
    }
    else
    {
    if(s>t[p].r || e<t[p].l)
    return 0;
    return query(p<<1,v,dep+1)+query((p<<1)+1,v,dep+1);
    }
    }
    int main()
    {
    // freopen("1.txt","r",stdin);
    int n,q,i,j,k,left,right,mid,result,p;
    while(scanf("%d %d",&n,&q)!=EOF)
    {
    for(i=1;i<=n;i++)
    scanf("%d",&key[i]);
    build(1,1,n,1);
    while(q--)
    {
    scanf("%d %d %d",&s,&e,&k);
    left=1; right=n;
    k--;
    p=0;
    while(left<right)
    {
    mid=(left+right+1)>>1;
    result=query(1,sort[1][mid],1);
    if(result==k && id[1][mid]>=s && id[1][mid]<=e)
    {
    p=1;
    printf("%d\n",sort[1][mid]);
    break;
    }
    if(result<=k)
    left=mid;
    else
    right=mid-1;
    }
    if(!p)
    printf("%d\n",sort[1][left]);

    }
    }
    return 0;
    }
  • 相关阅读:
    linux 查看磁盘空间大小
    linux查看防火墙状态及开启关闭命令
    运行安装mysql 报错 [root@localhost mysql-mult]# ./scripts/mysql_install_db  --defaults-file=conf/3306my.cnf FATAL ERROR: please install the following Perl modules before executing ./scripts/mysql_install_
    linux lsof命令详解
    centos6下无法使用lsof命令"-bash: lsof: command not found"
    服务器创建好后怎样使用远程连接工具链接的一些问题
    mysql在linux下的安装
    jmeter-linux下运行
    【WPF】一组CheckBox的全选/全不选功能
    【WPF】TabControl垂直分页栏/选项卡
  • 原文地址:https://www.cnblogs.com/lzhitian/p/2624059.html
Copyright © 2011-2022 走看看