划分树
老是忘 怕忘。。。
#include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> #include <iostream> #include <cstdlib> #include <string> #include <vector> using namespace std; #define N 100500 #define MID ((l+r)>>1) int a[N],s[N],t[20][N],num[20][N],n,m; void Build(int c,int l,int r) { int lm=MID-l+1,lp=l,rp=MID+1; //lm左长,lp左子左边,rp右子左边 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);//(l+s到l+s+ss内有答案,左边小的不属于它) 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\n",Query(0,1,n,l,r,k)); } return 0; }