HDU 4251 劃分樹
阿新 • • 發佈:2019-02-05
/* 劃分樹:解題型別單一,給出10^5個點,給你 q 個查詢,每次查詢出[l,r] 中第 k 大的值。 劃分樹: 主系列 4 3 2 5 8 7 6 1 9 排序後 1 2 3 4 5 6 7 8 9 中位數是 5 劃左邊 4 3 2 5 1 劃右邊 8 7 6 9 劃左邊 3 2 1 劃右邊 4 5 劃左邊 6 7 劃右邊 8 9 。。。。。。。 。。。。。。 參考部落格:http://www.2cto.com/kf/201210/160552.html */ #include<iostream> #include<algorithm> #include<cmath> #include<cstdio> using namespace std; #define manx 100009 int x[manx],tree[20][manx],sum_left[20][manx]; void make(int level,int left,int right){ if(left==right) return ; int mid = (left+right)>>1; int num = mid - left + 1; for(int i=left;i<=right;i++){ if(tree[level][i]<x[mid]) num--; } int lpos = left, rpos = mid+1; for(int i=left; i<=right; i++){ if(i==left) sum_left[level][i]=0; else sum_left[level][i]=sum_left[level][i-1]; if(tree[level][i]<x[mid]){ sum_left[level][i]++; tree[level+1][lpos++] = tree[level][i]; } else if(tree[level][i]>x[mid]) tree[level+1][rpos++] = tree[level][i]; else { if(num > 0){ num--; sum_left[level][i]++; tree[level+1][lpos++]=tree[level][i]; } else tree[level+1][rpos++]=tree[level][i]; } } make(level+1,left,mid); make(level+1,mid+1,right); } int query(int level,int left,int right,int l,int r,int k){ if(l==r) return tree[level][l]; int s, ss, mid = (left+right)>>1; if(left==l){ s = 0; ss = sum_left[level][r]; } else { s = sum_left[level][l-1]; ss = sum_left[level][r]-s; } int newl,newr; if(k<=ss){ newl = left + s; newr = left + s + ss - 1; return query(level+1,left,mid,newl,newr,k); } else { newl = mid + (l-left-s+1); newr = mid + (r-left-s-ss+1); return query(level+1,mid+1,right,newl,newr,k-ss); } } int main(){ int n,q,ca=0; while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++){ scanf("%d",&tree[0][i]); x[i] = tree[0][i]; } sort(x+1,x+n+1); make(0,1,n); scanf("%d",&q); printf("Case %d:\n",++ca); while(q--){ int l,r,k; scanf("%d%d",&l,&r); k = (r-l)/2 + 1; printf("%d\n",query(0,1,n,l,r,k)); } } }