歸併樹 O(logn*logn*logn) for each query,很慢的說,劃分樹版http://blog.csdn.net/leolin_/article/details/6696801
/*//1,建立歸併樹後我們得到了序列key[]的非降序排列,由於此時key[]內元素的rank是非遞減的,因此key[]中屬於指定區間[s,t]內的元素的rank也是非遞減的,所以我們可以用二分法枚舉key[]中的元素並求得它在[s,t]中的rank值,直到該rank值和詢問中的rank值相等;//2,那對於key[]中的某個元素val,如何求得它在指定區間[s,t]中的rank?這就要利用到剛建好的歸併樹:我們可以利用類似線段樹的query[s,t]操作找到所有屬於[s,t]的子區間,然後累加val分別在這些子區間內的rank,得到的就是val在區間[s,t]中的rank,注意到這和合并排序的合并過程一致;//3,由於屬於子區間的元素的排序結果已經記錄下來,所以val在子區間內的rank可以通過二分法得到。//上面三步經過了三次二分操作(query也是種二分),於是每次詢問的複雜度是O(log n *log n * log n)*/#define N 100005#define LogN 18int seq[LogN][N];int a[N];struct node{ int l,r;}t[N*3];void build(int id,int l,int r,int dep){ t[id].l = l; t[id].r = r; if(l == r){ seq[dep][l] = a[l]; return ; } int mid = (l+r)>>1; build(id<<1,l,mid,dep+1); build(id<<1|1,mid+1,r,dep+1); /*Merge Sort*/ int i,j,cnt; i = l,j = mid+1,cnt = l; while(i<=mid && j<=r){ if(seq[dep+1][i] < seq[dep+1][j]){ seq[dep][cnt++] = seq[dep+1][i++]; } else { seq[dep][cnt++] = seq[dep+1][j++]; } } if(i == mid+1){ while(j<=r){ seq[dep][cnt++] = seq[dep+1][j++]; } } else { while(i<=mid){ seq[dep][cnt++] = seq[dep+1][i++]; } }}int query(int id,int l,int r,int val,int dep){ if(l<=t[id].l && t[id].r<=r){ return lower_bound(&seq[dep][t[id].l], &seq[dep][t[id].r] + 1, val) - &seq[dep][t[id].l];//* } int mid = (t[id].l+t[id].r)>>1; int res = 0; if(l<=mid){ res += query(id<<1,l,r,val,dep+1); } if(r>mid){ res += query(id<<1|1,l,r,val,dep+1); } return res;}int main(){ int n,m; while(scanf("%d%d",&n,&m) != -1){ int i,j; for(i=1;i<=n;i++)scanf("%d",&a[i]); build(1,1,n,1); while(m--){ int s,t,k; scanf("%d%d%d",&s,&t,&k); k--;//*求第k大的話只要把這行改為k = t-s+1-k即可 int l = 1,r = n,mid; while(l<r){ mid = (l+r+1)>>1;//* int pos = query(1,s,t,seq[1][mid],1); if(pos<=k){ l = mid; } else r = mid-1; } printf("%d\n",seq[1][l]); } } return 0;}
http://codeforces.com/contest/85/problem/D——線段樹,有空過了它