划分树模板

划分树:一般用于快速求区间[a,b]第k大的数。

/****************-划分树模板-*****************/
//建树nlog(n) 查询log(n) 其实就是一种特殊形式的线段树
//使用方法参见main.
//isum表示区间内第[1,2,...k-1]的所有所有数之和(使用前先赋0)

#define MID(a,b) (a+((b-a)>>1))
typedef long long LL;
const int N=1e5+5;
struct P_Tree
{
    int n,order[N];
    int valu[20][N],num[20][N];
    LL sum[N],lsum[20][N],isum;
    void init(int len)
    {
        n=len;  sum[0]=0;
        for(int i=0;i<20;i++) valu[i][0]=0,num[i][0]=0,lsum[i][0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&order[i]);
            valu[0][i]=order[i];
            sum[i]=sum[i-1]+order[i];
        }
        sort(order+1,order+1+n);
        build(1,n,0);
    }
    void build(int lft,int rht,int ind)
    {
        if(lft==rht) return;
        
        int mid=MID(lft,rht);
        int same=mid-lft+1,ln=lft,rn=mid+1;
        for(int i=lft;i<=rht;i++)
            if(valu[ind][i]<order[mid]) same--;
        for(int i=lft;i<=rht;i++)
        {
            int flag=0;
            if((valu[ind][i]<order[mid])||(valu[ind][i]==order[mid]&&same))
            {
                flag=1;
                valu[ind+1][ln++]=valu[ind][i];
                lsum[ind][i]=lsum[ind][i-1]+valu[ind][i];
                if(valu[ind][i]==order[mid]) same--;
            }
            else
            {
                valu[ind+1][rn++]=valu[ind][i];
                lsum[ind][i]=lsum[ind][i-1];
            }
            num[ind][i]=num[ind][i-1]+flag;
        }
        build(lft,mid,ind+1);
        build(mid+1,rht,ind+1);
    }
    int query(int st,int ed,int k,int lft,int rht,int ind)
    {
        if(lft==rht) return valu[ind][lft];
        
        int mid=MID(lft,rht);
        int lx=num[ind][st-1]-num[ind][lft-1];//lx表示从lft到st-1这段区间内有多少个数进入左子树
        int ly=num[ind][ed]-num[ind][st-1];//ly表示从st到ed这段区间内有多少个数进入左子树
        int rx=st-1-lft+1-lx;//rx表示从lft到st-1这段区间内有多少个数进入右子树
        int ry=ed-st+1-ly;//ry表示从st到ed这段区间内有多少个数进入右子树
        if(ly>=k) return query(lft+lx,lft+lx+ly-1,k,lft,mid,ind+1);
        else
        {
            isum+=lsum[ind][ed]-lsum[ind][st-1];
            st=mid+1+rx;
            ed=mid+1+rx+ry-1;
            return query(st,ed,k-ly,mid+1,rht,ind+1);
        }
    }
}tree;

//int main()
//{
//    int n,m;
//    while(scanf("%d%d",&n,&m)!=EOF)
//    {
//        tree.init(n);
//        for(int i=0;i<m;i++)
//        {
//            int a,b,c;
//            scanf("%d%d%d",&a,&b,&c);
//            int res=tree.query(a,b,c,1,n,0);
//            printf("%d
",res);
//        }
//    }
//    return 0;
//}
原文地址:https://www.cnblogs.com/chenhuan001/p/5756075.html