题意: 给一个数组,对其进行多次查询。每次查询为(L,R,K),即在闭区间内[L,R]第K大的数。
思路:本来没什么思路的,然后学长说这是划分树的模板题,然后就没有然后了......
说一下自己对划分树的理解:
个人感觉划分树就是线段树的一种,每一个节点对应一段区间,节点内有两个数组num[],ans[]。
num[]为对应线段内的所有数据,按输入数据存放。
ans[]内存放的信息为对应线段的[ L, i ]内有多少个数被放到了其左子树中, L 为对应线段的最左边。
对于一段区间,首先找出该区间内的中位数,小于该数的放到其左子树中,大于该数的要放到右子树中。
若存在与中位数相同的数,则要按左右子树中数的个数来讨论,最终要保证左右子树数据量之差不超过 1。
中位数要放到那则可根据自己写线段树时的习惯而定。
查询过程:
对于给定的(L,R,K),判断[L,R]中有多少个数被放到了左子树中,总而得出第K个数被放到了左子树还
是右子树,总而确定下一次递归查询的范围。
每一次递归都要改变(L,R,K),直到L == R。
当 L == R时,节点内存住的数即为答案,递归查询结束。
其实,整个划分树的建立即为一个可以看作一次快速排序的过程,线段树的叶子节点从左到右即为按照一定规则排完序之后的序列。
下图中每一条线段托住的即为线段树中一个节点内的信息,上面为 对应的节点内ans[] 的信息。
#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> #include <cstdlib> #include <cstring> using namespace std; int num[101000],s[101000]; int stn[25][101000],ans[25][101000]; struct N { int l,r; } st[401000]; bool cmp(int a,int b) { return a < b; } void Init_St(int site,int l,int r,int h) { if(l == r) { st[site].l = l,st[site].r = r; stn[h][l] = s[l]; return; } st[site].l = l,st[site].r = r; int mid = (l+r)>>1 , i; int t1,t2; for(i = st[site].l,t1 = st[site].l,t2 = mid+1; i <= st[site].r ; ++i) { if(i == st[site].l) { if(stn[h][i] <= s[mid]) { ans[h][i] = 1; stn[h+1][t1++] = stn[h][i]; } else { ans[h][i] = 0; stn[h+1][t2++] = stn[h][i]; } } else { if(stn[h][i] <= s[mid]) { ans[h][i] = ans[h][i-1]+1; stn[h+1][t1++] = stn[h][i]; } else { ans[h][i] = ans[h][i-1]; stn[h+1][t2++] = stn[h][i]; } } } Init_St(site<<1,l,mid,h+1); Init_St(site<<1|1,mid+1,r,h+1); } int query(int site,int l,int r,int k,int h) { if(l == r) { return stn[h][l]; } int mid = (st[site].l + st[site].r)>>1; if(k <= ans[h][r] - (l != st[site].l ? ans[h][l-1] : 0)) { return query(site<<1,(l == st[site].l ? l : st[site].l+ans[h][l-1]),st[site].l-1+ans[h][r],k,h+1); } else { return query(site<<1|1,(l == st[site].l ? mid+1 : mid+l-st[site].l+1-ans[h][l-1]),mid+r-st[site].l+1-ans[h][r],k-(ans[h][r]-(l == st[site].l ? 0 : ans[h][l-1])),h+1); } } int main() { int i,n,m,l,r,k; while(scanf("%d %d",&n,&m) != EOF) { for(i = 1; i <= n; ++i) { scanf("%d",&num[i]); s[i] = num[i]; } sort(s+1,s+n+1,cmp); for(i = 1; i <= n; ++i) { stn[0][i] = num[i]; } Init_St(1,1,n,0); while(m--) { scanf("%d %d %d",&l,&r,&k); printf("%d\n",query(1,l,r,k,0)); } } return 0; }