HDU4417 Super Mario
划分树模板题
1 #include<cstdio> 2 #include<string> 3 #include<vector> 4 #include<algorithm> 5 #define N 100009 6 using namespace std; 7 int n; 8 int arr[N];//原数据 9 int od[N];//排序后 10 int lfnum[20][N];//元素所在区间的当前位置进入左孩子的元素的个数 11 int val[20][N];//记录第k层当前位置的元素的值 12 bool cmp(const int &x,const int &y) 13 { 14 return arr[x]<arr[y]; 15 } 16 void build(int l,int r,int d) 17 { 18 if(l==r) return; 19 int mid=(l+r)>>1,p=0; 20 for(int i=l; i<=r; i++) 21 { 22 if(val[d][i]<=mid) 23 { 24 val[d+1][l+p]=val[d][i]; 25 lfnum[d][i]=++p; 26 } 27 else 28 { 29 lfnum[d][i]=p; 30 val[d+1][mid+i+1-l-p]=val[d][i]; 31 } 32 } 33 build(l,mid,d+1); 34 build(mid+1,r,d+1); 35 } 36 //求区间[s,e]第k大的元素 37 int query(int s,int e,int k,int l=1,int r=n,int d=0) 38 { 39 if(l==r) return l; 40 int mid=(l+r)>>1,ss,ee; 41 ss=(s==l?0:lfnum[d][s-1]); 42 ee=lfnum[d][e]; 43 if(ee-ss>=k) return query(l+ss,l+ee-1,k,l,mid,d+1); 44 return query(mid+1+(s-l-ss),mid+1+(e-l-ee),k-(ee-ss),mid+1,r,d+1); 45 } 46 int main() 47 { 48 int cas=0,m,l,r,T,ql,qr; 49 scanf("%d",&T); 50 while(T--) 51 { 52 printf("Case %d:\n",++cas); 53 scanf("%d%d",&n,&m); 54 for(int i=1; i<=n; i++) scanf("%d",arr+i),od[i]=i; 55 sort(od+1,od+n+1,cmp); 56 for(int i=1; i<=n; i++) val[0][od[i]]=i; 57 build(1,n,0); 58 while(m--) 59 { 60 int num,v; 61 scanf("%d%d%d",&ql,&qr,&v); 62 ql++;qr++; 63 l=1,r=qr-ql+1; 64 while(l<=r) 65 { 66 int mid=(l+r)>>1; 67 num=query(ql,qr,mid); 68 if(arr[od[num]]>v) r=mid-1; 69 else l=mid+1; 70 } 71 printf("%d\n",r); 72 } 73 } 74 }