划分树模板


#include <iostream>  
#include <algorithm>  
#include <string.h>  
#include <stdio.h>  
  
using namespace std;  
const int MAXN = 1e5+10;  
int a[MAXN],sorted[MAXN];  
struct Trie{  
    int num[20][MAXN];//进入左区间的数量  
    int val[20][MAXN];//记录第i层元素序列  
    int lsum[20][MAXN];  
    int isum;  
    void init(int n){  
        for(int i = 1; i <= n; ++i){  
            val[0][i] = a[i];  
        }  
        for(int i = 0; i < 20; ++i){  
            lsum[i][0] = 0,num[i][0] = 0,val[i][0] = 0;  
        }  
    }  
    void build(int l,int r,int deep){  
        if(l == r)return ;  
        int mid = (l+r)>>1;  
        int lnum = mid-l+1;  
        for(int i = l; i <= mid; ++i){  
            if(sorted[i] < sorted[mid]){  
                lnum--;  
            }  
        }  
        int lp = l,rp = mid+1;  
        for(int i = l; i <= r; ++i){  
            lsum[deep][i] = lsum[deep][i-1];  
            num[deep][i] = num[deep][i-1];  
            if((val[deep][i] < sorted[mid])||(val[deep][i]==sorted[mid]&&lnum)){  
                val[deep+1][lp++] = val[deep][i];  
                lsum[deep][i] += val[deep][i];  
                num[deep][i]++;    
                if(val[deep][i]==sorted[mid]) lnum--;  
            }  
            else{  
                val[deep+1][rp++] = val[deep][i];  
            }  
        }  
        build(l,mid,deep+1);  
        build(mid+1,r,deep+1);  
    }  
    int query(int deep,int l,int r,int lp,int rp,int k){  
        int s,ss;  
        if(l == r) return val[deep][l];  
        s = num[deep][lp-1]-num[deep][l-1];  
        ss = num[deep][rp]-num[deep][lp-1];  
        int mid = (l+r)>>1;  
        if(k <= ss){  
        // 左区间   
            return query(deep+1,l,mid,l+s,l+s+ss-1,k);  
        }  
        else{  
        //右区间  
        //mid+1 + (lp-1-l+1-s);  
        //mid+1 + (lp-1-l+1-s) + (rp-lp+1-ss) - 1  
            isum += (lsum[deep][rp]-lsum[deep][lp-1]);  
            return query(deep+1,mid+1,r,mid-l+1-s+lp,mid-l+1+rp-s-ss,k-ss);  
        }  
    }  
};  
Trie tree;  
int main(){  
    int i, j, k;   
    int n,m;   
    while(~scanf("%d%d", &n, &m)){    
        for (i = 1; i <= n; i++){    
            scanf("%d", &a[i]);    
            sorted[i] = a[i];  
        }    
        tree.init(n);  
        sort(sorted + 1, sorted + 1 + n);    
        tree.build(1,n,0);  
        while(m--){    
            tree.isum = 0;  
            scanf("%d%d%d",&i,&j,&k);// i,j分别为区间起始点,k为该区间第k小的数。    
            int res = tree.query(0, 1, n, i, j, k);  
            printf("%d,%d\n",res,tree.isum);    
        }    
    }   
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值