zoukankan      html  css  js  c++  java
  • POJ 2104 Kth Number【划分树】


    http://poj.org/problem?id=2104
    POJ 2104 K-th Number
    大意:有n个数字排成一列,有m个询问,格式为:
    left right k
    即问在区间[left,right]第k大的数据为多少?

    分析:划分树
    具体的介绍开心->OK介绍得很清楚,这里把他PPT里的部分贴上来,邪恶一把,嘿嘿。。
    建图:
    建树的过程比较简单,对于区间[l,r],首先通过对原数组的排序找到这个区间的中位数a[mid],小于a[mid]的数划入它的左子树[l,mid-1],大于它的划入右子树[mid,r]。
    同时,对于第i个数a[i],记录在[l,i]区间内有多少数被划入左子树。最后,对它的左子树区间[l,mid-1]和右子树区间[mid,r]递归的继续建树就可以了。
    建树的时候要注意,对于被分到同一子树的元素,元素间的相对位置不能改变。

    查找的过程中主要问题就是确定将要查找的区间。
    查找深度为dep,在大区间[L ,R]中找小区间[l ,r]中的第k元素。
    我们的想法是,先判断[l ,r]中第k元素在[L ,R]的哪个子树中,然后找出对应的小区间和k,递归的进行查找,直到小区间的l==r为止。
    通过之前的记录可以知道,在区间[L,l-1]中有(toleft[dep][l-1]-toleft[dep][L-1])进入左子树,
    记它为x。

    同理区间[L,r]中有(toleft[dep][r]-toleft[dep][L-1])个数进去左子树,记它为y。
    所以,我们知道区间小区间[l,r]中有(y-x)个数进入左子树。那么如果(y-x)>=k,那么就在左子树中继续查找,否则就在右子树中继续查找。

      接着,解决查找的小区间的问题。
      如果接下来要查找的是左子树,那么小区间应该是[L+([L,l-1]区间进入左子树的个数),L+([L,r]区间内进入左子树的个数)-1]。即区间[L+x,L+y-1]。
        显然,这里k不用变。
      如果接下来要查找的是右子树,那么小区间应该是[mid+([L,l-1]区间中进入右子树的个数),mid+([L,r]区间进入右子树的个数)-1]。
        即区间[mid+(l-L-x),mid+(r-L-y)]。
        显然,这里k要减去区间里已经进入左子树的个数,即k变为k-(y-x)。

    POJ 2104 Code
    #include<stdio.h>
    #include
    <string.h>
    #include
    <algorithm>
    using namespace std;
    const int MAXN = 100000+10;
    int tree[22][MAXN],toleft[22][MAXN];
    int sorted[MAXN];//已经排好序的数据
    void build_tree(int left,int right,int deep)//建树
    {
    if(left==right)return;
    int mid = (left+right)>>1;
    int i;
    int same = mid-left+1;//位于左子树的数据
    for(i=left;i<=right;i++) //计算放于左子树中与中位数相等的数字个数
    {
    if(tree[deep][i]<sorted[mid])
    same
    --;
    }

    int ls = left;
    int rs = mid+1;
    for(i=left;i<=right;i++)
    {
    int flag = 0;
    if((tree[deep][i]<sorted[mid])||(tree[deep][i]==sorted[mid]&&same>0))
    {
    flag
    = 1;
    tree[deep
    +1][ls++] = tree[deep][i];
    if(tree[deep][i]==sorted[mid])same--;
    }
    else
    {
    tree[deep
    +1][rs++] = tree[deep][i];
    }

    toleft[deep][i]
    =toleft[deep][i-1]+flag;
    }

    build_tree(left,mid,deep
    +1);
    build_tree(mid
    +1,right,deep+1);
    }

    int query(int left,int right,int k,int L,int R,int deep)
    {
    if(left==right)return tree[deep][left];
    int mid = (L+R)>>1;
    int x = toleft[deep][left-1]-toleft[deep][L-1];//位于left左边的放于左子树中的数字个数
    int y = toleft[deep][right] - toleft[deep][L-1];//到right为止位于左子树的个数
    int ry = right-L-y;//到right右边为止位于右子树的数字个数
    int cnt = y-x;//[left,right]区间内放到左子树中的个数
    int rx = left-L-x;//left左边放在右子树中的数字个数
    if(cnt>=k)
    return query(L+x,L+y-1,k,L,mid,deep+1);
    else
    return query(mid+rx+1,mid+1+ry,k-cnt,mid+1,R,deep+1);

    }

    int main()
    {
    int n,m;
    while(scanf("%d%d",&n,&m) == 2)
    {
    int i;

    for(i=1;i<=n;i++)
    {
    scanf(
    "%d",&sorted[i]);
    tree[
    0][i] = sorted[i];
    }

    sort(sorted
    +1,sorted+n+1);
    build_tree(
    1,n,0);
    while(m--)
    {
    int left,right,k;
    scanf(
    "%d%d%d",&left,&right,&k);
    printf(
    "%d\n",query(left,right,k,1,n,0));
    }
    }
    return 0;
    }
  • 相关阅读:
    DB设计原则
    英文地址[转]
    ICollection
    雅虎优化14条
    vue过滤器
    php中echo(),print(),print_r()之间的区别
    jQ中对attr()方法的理解
    浅析call和apply的不同
    浅析call和apply
    PHP是弱类型语言,自动转换,强制转换
  • 原文地址:https://www.cnblogs.com/AndreMouche/p/1971291.html
Copyright © 2011-2022 走看看