划分树

来源:互联网 发布:海隆软件 编辑:程序博客网 时间:2024/05/02 00:40

虽然sunshine大神说划分树只是用来求第k小数这一个用处,但还是好好学习!!;

划分树建树的过程就是一个模拟快排的过程。

在建树的过程中,需要先取中间值,然后,小于中间值的放在左边,大于中间值的放在右边,在这个过程中,还需要记录第d层第i个树之前的左边的数。

这里写图片描述

这里写图片描述

poj 2104
下面写程序

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define maxn 101000using namespace std;struct node{    int s[maxn],c[maxn];};node t[50];int a[maxn];void build(int p,int l,int r){    if(l==r)return ;    int mid=l+r>>1,x=l,y=mid+1;    int nm=0,cnt=0;    for(int i=mid;a[i]==a[mid];i--)nm++;    for(int i=l;i<=r;i++)    {        if(t[p].s[i]<a[mid])        {            t[p+1].s[x++]=t[p].s[i];            cnt++;            t[p].c[i]=cnt;            continue;        }        if(t[p].s[i]>a[mid])        {            t[p+1].s[y++]=t[p].s[i];            t[p].c[i]=cnt;            continue;        }        if(nm)        {            t[p+1].s[x++]=t[p].s[i];            cnt++;            t[p].c[i]=cnt;            nm--;        }         else         {            t[p+1].s[y++]=t[p].s[i];            t[p].c[i]=cnt;        }    }    build(p+1,l,mid);    build(p+1,mid+1,r);}int num(int l,int r,int k,int p,int b,int e){    if(l==r)return t[p].s[l];    int mid=b+e>>1,s,ss;    if(l==b)        {s=0;ss=t[p].c[r];}    else{s=t[p].c[l-1];ss=t[p].c[r]-s;}    if(k<=ss)    {           return num(b+s,b+s+ss-1,k,p+1,b,mid);    }    else     {           return num(mid+l-b-s+1,mid+r-ss-s-b+1,k-ss,p+1,mid+1,e);    }}int main(){    int n,m;    scanf("%d%d",&n,&m);    int cnt=0;    for(int i=1;i<=n;i++)           {        scanf("%d",&t[1].s[i]);        a[++cnt]=t[1].s[i];    }    sort(a+1,a+cnt+1);    build(1,1,n);    while(m--)    {        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        printf("%d\n",num(x,y,z,1,1,n));    }    return 0;}
0 0