这个题也是求区间k小数,用划分树做
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=100100; int n,m,sorted[maxn],tree[23][maxn],toleft[23][maxn]; void Build(int l,int r,int deep) { if(l==r) return; int mid=(l+r)>>1; int same=mid-l+1; for(int i=l;i<=r;i++) if(tree[deep][i]<sorted[mid]) same--; int ls=l,rs=mid+1; for(int i=l;i<=r;i++) { toleft[deep][i]=toleft[deep][i-1]; if(tree[deep][i]<sorted[mid]) { tree[deep+1][ls++]=tree[deep][i]; toleft[deep][i]++; } else if(tree[deep][i]==sorted[mid]) { if(same) { tree[deep+1][ls++]=tree[deep][i]; toleft[deep][i]++; same--; } else tree[deep+1][rs++]=tree[deep][i]; } else tree[deep+1][rs++]=tree[deep][i]; } Build(l,mid,deep+1); Build(mid+1,r,deep+1); } int Query(int l,int r,int L,int R,int deep,int k) { if(l==r) return tree[deep][l]; int mid=(L+R)>>1; int x=toleft[deep][l-1]-toleft[deep][L-1]; int y=toleft[deep][r]-toleft[deep][L-1]; int ry=r-L-y; int rx=l-L-x; int cnt=y-x; if(cnt>=k) return Query(L+x,L+y-1,L,mid,deep+1,k); else return Query(mid+rx+1,mid+ry+1,mid+1,R,deep+1,k-cnt); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++) { scanf("%d",&sorted[i]); tree[0][i]=sorted[i]; } sort(sorted+1,sorted+1+n); Build(1,n,0); while(m--) { int a,b,k; scanf("%d%d%d",&a,&b,&k); printf("%d\n",Query(a,b,1,n,0,k)); } } return 0; }