• [划分树] POJ 2104 K-th Number


    K-th Number
    Time Limit: 20000MS   Memory Limit: 65536K
    Total Submissions: 51732   Accepted: 17722
    Case Time Limit: 2000MS

    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

    Hint

    This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.

    Source

    Northeastern Europe 2004, Northern Subregion
     
    原题大意:给一组数。对于每个查询区间,找出第k小的数。
    解题思路:划分树或主席树的裸题,POJ还有一个类似的题目 POJ 2761.
                  这两道题的代码一样都可以过。
                  所谓划分树,类似于在已经知道区间中位数的情况下的快排,比中位数小的都放左边,大的分右边,相等的看看左边有没有空,有空放左边,没空放右边,相对位置不变,并记录每次的左右子树划分情况。
                  如果所求第k小的树,每次我们看看有多少数在左边,就可以知道该查左区间还是右区间。对查询区间做了处理后递归下去即可得出唯一的数值。
    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    int tree[20][110001],sorted[110001],left[20][110001];
    void build(int dep,int l,int r)
      {
      	 int mid=(l+r)>>1,i,midnum=mid-l+1,sonl=l,sonr=mid+1;
      	 for(i=l;i<=r;++i) if(sorted[i]<sorted[mid]) --midnum;  //寻找能放入左子树中值的个数
      	 for(i=l;i<=r;++i)
      	   {
     if(i==l) left[dep][i]=0; else left[dep][i]=left[dep][i-1]; //对不同的区间,进行左 
    //树个数初始化
      	   	  if(tree[dep][i]==sorted[mid]) 
      	   	    {
      	   	       if(midnum)
      	   	         {
      	   	         	--midnum;
      	   	         	++left[dep][i];
                        tree[dep+1][sonl++]=tree[dep][i]; //统计进入左子树的个数,并更新//下一层树
    				 } else tree[dep+1][sonr++]=tree[dep][i]; 
    		    } else
    		  if(tree[dep][i]<sorted[mid])                 //比中间值小,入左子树
    		    {
    		      ++left[dep][i];
    		      tree[dep+1][sonl++]=tree[dep][i];       
    			} else tree[dep+1][sonr++]=tree[dep][i];   //比中间值小,入右子树
    	   }
    	 if(l==r) return;                                //如果是叶子结点,返回
    	 build(dep+1,l,mid);                            //递归左右子树
    	 build(dep+1,mid+1,r);                         
      }
    int query(int dep,int l,int r,int ql,int qr,int k)
      {
      	 int l_ql,ql_qr,mid=(l+r)>>1;
      	 if(l==r) return tree[dep][l];                      //如果找到值,返回
      	 if(l==ql)                                     //恰好是所求左区间为递归左区间
      	   {                                         //
      	   	  l_ql=0;
      	   	  ql_qr=left[dep][qr];
    	   } else
    	   {
    	   	  l_ql=left[dep][ql-1];                     //l到ql-1的入左区间数
    	   	  ql_qr=left[dep][qr]-l_ql;                  //ql到qr的左区间数
    	   }
    	 if(k<=ql_qr) return query(dep+1,l,mid,l+l_ql,l+l_ql+ql_qr-1,k); else   //递归下一区间
    	 return query(dep+1,mid+1,r,mid+1+ql-l_ql-l,mid+1+qr-ql_qr-l_ql-l,k-ql_qr);
        //右区间有点乱,ql-l-l_ql即l到ql-1中入右区间的个数依次类推
      }
    int main()
      {
      	int n,m,i,ql,qr,qk;
      	scanf("%d%d",&n,&m);
      	for(i=1;i<=n;++i)
      	  {
      	  	scanf("%d",&tree[0][i]);
      	  	sorted[i]=tree[0][i];
    	  }
    	sort(sorted+1,sorted+n+1);
    	build(0,1,n);
    	while(m--)
    	  {
    	  	 scanf("%d%d%d",&ql,&qr,&qk);
    	  	 printf("%d
    ",query(0,1,n,ql,qr,qk));
    	  }
      	return 0;
      }
    

      

  • 相关阅读:
    Play Framework + ReactiveMongo 环境搭建
    阿里前端二面(笔试/机试)总结
    ES 6 新特性整理
    Javascript Dom 相关知识整理
    Ajax、CORS、Comet和WebSocket
    XHTML 1.0 标签语义
    Javascript知识整理
    Javascript性能优化(一)
    CSS知识整理
    绘制标准的d3图表
  • 原文地址:https://www.cnblogs.com/fuermowei-sw/p/6213153.html
Copyright © 2020-2023  润新知