划分树 模板


划分树——给出n个数,m个询问。每次询问区间[x,y]中第k小的数是多少。


在 [ 2 4 3 5 8 1 7 6 ] 中找区间[2,7]的第2小
①           [ 2 4 3 5 8 1 7 6 ]            // 原数组  [2,7]找第2小
②     [ 2 4 3 1 ]         [ 5 8 7 6 ]      // 分成左右两组  知道[2,7]中有3个到左子树  故在答案左
③  [ 2 1 ]   [ 4 3 ]    [ 5 6 ]  [ 8 7 ]   // 同理  仅仅有1个到左子树  故答案在右子树
④  [1] [2]   [3] [4]    [5] [6]  [7] [8]   // 一直迭代直到找到答案


#include <iostream> 
#include <cstdio> 
#include <algorithm> 
using namespace std; 
   
#define N 100500 
   
#define MID ((l+r)>>1) 
int a[N],s[N],t[20][N],num[20][N],n,m; 
/*
建树:对于区间[l,r]。首先通过对原数组的排序找到这个区间的中位数a[mid]。
小于a[mid]的数划入他的左子树[l,mid-1],大于它的划入右子树[mid,r]。

同一时候, 对于第i个数,记录在[l,i]区间内有多少数被划入左子树。

最后。 对它的左子树区间[l,mid-1]和右子树区间[mid,r]递归的继续建树就能够了。 */ // 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)//子区间[st,ed],大区间[lft,rht],层数ind // { // if(lft==rht) return valu[ind][lft]; // // int mid=MID(lft,rht); // int lx=num[ind][st-1]-num[ind][lft-1];//在左区间不属于子区间的个数 // int ly=num[ind][ed]-num[ind][st-1];//有多少个进入左区间 // int rx=st-1-lft+1-lx;//在右区间不属于子区间的个数 // int ry=ed-st+1-ly;//有多少个进入右区间 // 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); // } // } void Build(int c,int l,int r) { int lm=MID-l+1,lp=l,rp=MID+1; for(int i=l;i<=MID;i++) lm-=s[i]<s[MID]; for(int i=l;i<=r;i++) { if( i==l ) num[c][i]=0; else num[c][i]=num[c][i-1]; if( t[c][i]==s[MID] ) { if( lm ) { lm--; num[c][i]++; t[c+1][lp++]=t[c][i]; } else t[c+1][rp++]=t[c][i]; } else if( t[c][i]<s[MID] ) { num[c][i]++; t[c+1][lp++]=t[c][i]; } else t[c+1][rp++]=t[c][i]; } if( l<r ) Build(c+1,l,MID),Build(c+1,MID+1,r); } int Query(int c,int l,int r,int ql,int qr,int k) { if( l==r ) return t[c][l]; int s,ss; if( l==ql ) s=0,ss=num[c][qr]; else s=num[c][ql-1],ss=num[c][qr]-num[c][ql-1]; if( k<=ss ) return Query(c+1,l,MID,l+s,l+s+ss-1,k); else return Query(c+1,MID+1,r,MID+1+ql-l-s,MID+1+qr-l-s-ss,k-ss); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); s[i]=t[0][i]=a[i]; } sort(s+1,s+1+n); Build(0,1,n); while( m-- ) { int l,r,k; scanf("%d%d%d",&l,&r,&k); printf("%d ",Query(0,1,n,l,r,k)); } return 0; }


原文地址:https://www.cnblogs.com/mfrbuaa/p/5314000.html