当前位置:编程学习 > C/C++ >>

POJ 2104 K-th Number 归并树与划分树

第一次接触,自己也没啥好总结的,都是看网上的资料。
归并树是在建树的过程中保存归并排序。
划分树是在建树的过程中保存快速排序。
其中归并树适合解决一个数在某个区间的名次。
划分树适合解决某个区间的K大数。
POJ这题是找K大数,归并树也可做,二分答案,再由归并树找出这个数的名次。划分树更快。
对于HDU 2665,我写的归并树总之是过不去。
归并树:
[cpp] 
#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<queue> 
#include<map> 
#include<stack> 
#include<algorithm> 
#include<string> 
#define LL long long 
#define LD long double 
#define eps 1e-7 
#define inf 1<<30 
#define MOD 1000000007 
#define N 100005 
using namespace std; 
struct MergeTree{ 
    int left,right,mid; 
}tree[N*4]; 
int num[N],mer[20][N]; 
int n,q; 
void create(int step,int l,int r,int deep){ 
    tree[step].left=l; 
    tree[step].right=r; 
    tree[step].mid=(l+r)>>1; 
    if(l==r){ 
        mer[deep][l]=num[l]; 
        return; 
    } 
    create(step<<1,l,(l+r)/2,deep+1); 
    create((step<<1)|1,(l+r)/2+1,r,deep+1); 
    int i=l,j=(l+r)/2+1,p=l; 
    //归并排序,在建树的时候保存 
    while(i<=(l+r)/2&&j<=r){ 
        if(mer[deep+1][i]>mer[deep+1][j]) 
            mer[deep][p++]=mer[deep+1][j++]; 
        else 
            mer[deep][p++]=mer[deep+1][i++]; 
    } 
    while(i<=(l+r)/2) 
        mer[deep][p++]=mer[deep+1][i++]; 
    while(j<=r) 
        mer[deep][p++]=mer[deep+1][j++]; 

int query(int step,int l,int r,int deep,int key){ 
    if(tree[step].right<l||tree[step].left>r) 
        return 0; 
    if(tree[step].left>=l&&tree[step].right<=r) 
        //找到key在排序后的数组中的位置 
        return lower_bound(&mer[deep][tree[step].left],&mer[deep][tree[step].right]+1,key)-&mer[deep][tree[step].left]; 
    return query(2*step,l,r,deep+1,key)+query(2*step+1,l,r,deep+1,key); 

int slove(int l,int r,int k){ 
    int high=n,low=1,mid; 
    //二分答案 
    while(low<high){ 
        mid=(low+high+1)>>1; 
        int cnt=query(1,l,r,1,mer[1][mid]); 
        if(cnt<=k) 
            low=mid; 
        else 
            high=mid-1; 
    } 
    return mer[1][low]; 

int main(){ 
    while(scanf("%d%d",&n,&q)!=EOF){         
        for(int i=1;i<=n;i++) 
            scanf("%d",&num[i]); 
        create(1,1,n,1); 
        while(q--){ 
            int l,r,k; 
            scanf("%d%d%d",&l,&r,&k); 
            printf("%d\n",slove(l,r,k-1)); 
        } 
    } 
    return 0; 

划分树:
[cpp] 
#include<iostream> 
#include<cstring> 
#include<cstdio> 
#include<algorithm> 
#define N 100005 
using namespace std; 
struct Node{ 
    int left,right,mid; 
}tree[N*4]; 
int sa[N],num[20][N],cnt[20][N]; //sa中是排序后的,num记录每一层的排序结果,cnt[deep][i]表示第deep层,前i个数中有多少个进入左子树 
int n,q; 
void debug(int d){ 
    for(int i=1;i<=n;i++) 
        printf("%d ",num[d][i]); 
    printf("\n"); 

void bulid(int step,int l,int r,int deep){ 
    tree[step].left=l; 
    tree[step].right=r; 
    tree[step].mid=(l+r)>>1; 
    if(l==r) 
        return; 
    int mid=(l+r)>>1; 
    int mid_val=sa[mid],lsum=mid-l+1;; 
    for(int i=l;i<=r;i++) 
        if(num[deep][i]<mid_val) 
            lsum--;    //lsum表示左子树中还需要多少个中值 
    int L=l,R=mid+1; 
    for(int i=l;i<=r;i++){ 
        if(i==l) 
            cnt[deep][i]=0; 
        else 
            cnt[deep][i]=cnt[deep][i-1]; 
        if(num[deep][i]<mid_val||(num[deep][i]==mid_val&&lsum>0)){  //左子树 
            num[deep+1][L++]=num[deep][i]; 
            cnt[deep][i]++; 
            if(num[deep][i]==mid_val) 
                lsum--; 
        } 
        else 
            num[deep+1][R++]=num[deep][i]; 
    } 
//  debug(deep); 
    bulid(2*step,l,mid,deep+1); 
    bulid(2*step+1,mid+1,r,deep+1); 

int query(int step,int l,int r,int k,int deep){ 
    if(l==r) 
        return n

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,