hdu 2665 Kth number(划分树)

题意:给定一列数,每次查询区间[s,t]中的第k大;

参考:http://www.cnblogs.com/kane0526/archive/2013/04/20/3033212.html

http://www.cnblogs.com/kuangbin/archive/2012/08/14/2638829.html

思路:快排思想+线段树=划分树,也就是树的每一层都按规则划分;

对于本题,建树前,保存原数列排序后的数列,原数列作为树的顶层;

建树时,考虑当前区间中的中间值,若大于中间值,在下一层中放右边,否则放左边,实现划分;

维护每层中1到i中小于区间中间数的个数(区间左边的数),方便查询时计算;

查询时,比较待查询区间与当前区间中左边数的个数,以便查询子区间;

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int tree[30][100010];
int as[100010];
int toleft[30][100010];
void build(int l,int r,int dep)
{
    if(l==r)return;
    int mid=(l+r)/2;
    int same=mid-l+1;//表示等于中间值而且被分入左边的个数
    for(int i=l;i<=r;i++)
      if(tree[dep][i]<as[mid])
         same--;   //目的是标记在左边的数
    int lpos=l;
    int rpos=mid+1;
    for(int i=l;i<=r;i++)
    {
        if(tree[dep][i]<as[mid])//比中间的数小,分入左边
             tree[dep+1][lpos++]=tree[dep][i];
        else if(tree[dep][i]==as[mid]&&same>0)//相等,放左边
        {
            tree[dep+1][lpos++]=tree[dep][i];
            same--;
        }
        else  //比中间值大分入右边
            tree[dep+1][rpos++]=tree[dep][i];
        toleft[dep][i]=toleft[dep][l-1]+lpos-l;//从1到i放左边的个数

    }
    build(l,mid,dep+1);
    build(mid+1,r,dep+1);

}
int query(int L,int R,int l,int r,int pos,int k){
   if(l==r) return tree[pos][l];
   int mid=(L+R)/2; //注意
   int cnt=toleft[pos][r]-toleft[pos][l-1]; //待查询区间中左边的数的个数
   if(cnt>=k){         //不够,扩大区间
      int newl=L+toleft[pos][l-1]-toleft[pos][L-1]; //查询区间向左移
      int newr=newl+cnt-1;
      return query(L,mid,newl,newr,pos+1,k);
   }
   else{  //多余,缩小区间
      int newr=r+toleft[pos][R]-toleft[pos][r]; //查询区间向右移
      int newl=newr-(r-l-cnt);
      return query(mid+1,R,newl,newr,pos+1,k-cnt);
   }
}
int main(){
    int n,m,i,j,k,a,b,c,t;
    scanf("%d",&t);
    while(t--){
        memset(tree,0,sizeof(tree));
       scanf("%d%d",&n,&m);
       for(i=1;i<=n;i++) {
            scanf("%d",&tree[0][i]); //顶层
            as[i]=tree[0][i];
       }
       sort(as+1,as+n+1); //快排
       build(1,n,0);
       for(i=0;i<m;i++){
         scanf("%d%d%d",&a,&b,&c);
         printf("%d\n",query(1,n,a,b,0,c));
       }
    }
    return 0;
}
时间: 2024-10-05 00:22:19

hdu 2665 Kth number(划分树)的相关文章

HDU 2665 Kth number 主席树裸题

题目链接 主席树详解 每次插入logn个点 这样就不需要重新建树了. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <fstream> #include <string> #include <time.h> #include <vector> #include <map> #include &

HDU 2665 Kth number (主席树)

题意:给定一个序列,求给定区间的第 k 小的值. 析:就是一个主席树的裸板. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring&g

hdu 2665 Kth number(划分树)

Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4602 Accepted Submission(s): 1468 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first l

poj 2104 K-th Number(划分树模板)

划分树模板题,敲上模板就ok了. #include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #define MP

hdu 2665 Kth number (poj 2104 K-th Number) 划分树

划分树的基本功能是,对一个给定的数组,求区间[l,r]内的第k大(小)数. 划分树的基本思想是分治,每次查询复杂度为O(log(n)),n是数组规模. 具体原理见http://baike.baidu.com/link?url=vIUKtsKYx7byeS2KCOHUI14bt_0sdHAa9BA1VceHdGsTv5jVq36SfZgBKdaHYUGqIGvIGrE_aJtqy0D0b1fCoq 个人感觉看代码是最好的学习方法. #include <cstdio> #include <c

POJ 2104&amp;HDU 2665 Kth number(主席树入门+离散化)

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 50247   Accepted: 17101 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

HDU 2665.Kth number 区间第K小

Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11394    Accepted Submission(s): 3465 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The f

hdoj 2665 Kth number主席树裸

Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 9417    Accepted Submission(s): 2938 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The fi

杭电ACM2665——Kth number~~划分树

题目的意思:给点区间[a, b],查找第K大的数,和POJ2104题一样,只是HDU上的时间限制5000MS,用我在POJ上的方法,过不了,会超时. 而这一题的代码,改一下main函数的输入,就可以直接AC了POJ上的2104. 这题,用分桶法,WR,纠结了一晚上,最后还是放弃了,实在不知道错在哪里.于是改用了划分树的方法,学习了划分树的建立和查找. 划分树:主要运用于求解序列中区间[a, b]上的第K大的数,也就是区间[a, b]从小到大排序,第K个. 主要的算法思路是: 1,建树:先排序好存