题目链接:
Kth number
Time Limit: 15000/5000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
Problem Description
Give you a sequence and ask you the kth big number of a inteval.
Input
The first line is the number of the test cases.
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere.
The second line contains n integers, describe the sequence.
Each of following m lines contains three integers s, t, k.
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere.
The second line contains n integers, describe the sequence.
Each of following m lines contains three integers s, t, k.
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]
Output
For each test case, output m lines. Each line contains the kth big number.
Sample Input
1
10 1
1 4 2 3 5 6 7 8 9 0
1 3 2
Sample Output
2
题意:
给一个数列,问区间[l,r]内的第k大的数;
思路:
划分树的模板题;据说可以用可持久化线段树做,就是那个好难理解(看别人博客说创造可持久化线段树的居然说划分树好难理解,然后自己yy了可持久化线段树,简直丧心病狂),所以我就先学的划分树,划分树的思想跟快速排序很相似,用一个二维数组进行快速排序,另外的一个二维数组记录在排序的过程中有多少个数排在了左边,查找的时候就可以利用这个二维数组进行,真的是好神奇;
AC代码:
/*
608MS | 16072K | 1761 B | G++ | 2014300227 |
*/
#include <bits/stdc++.h> using namespace std; const int N=1e5+4; typedef long long ll; int n,m,a[N],sorted[N],k; int tree[32][N],num[32][N]; void build(int dep,int l,int r) { if(l>=r)return ; int mid=(l+r)>>1; int lp=l,rp=mid+1,sum=mid-l+1;//sum表示与sorted[mid]相等并且放在左边的个数;初始化为(r-l+1)/2,即左边的容量; for(int i=l;i<=r;i++) { if(tree[dep][i]<sorted[mid])sum--;//把放在左边的小于sorted[mid]的减去,剩下的就是==sorted[mid]的; } for(int i=l;i<=r;i++) { if(i!=l)num[dep][i]=num[dep][i-1]; else num[dep][i]=0; if(tree[dep][i]<sorted[mid]) { tree[dep+1][lp++]=tree[dep][i]; num[dep][i]++; } else if(tree[dep][i]==sorted[mid]&&sum>0) { tree[dep+1][lp++]=tree[dep][i]; num[dep][i]++; sum--; } else { tree[dep+1][rp++]=tree[dep][i]; } } build(dep+1,l,mid), build(dep+1,mid+1,r); } int query(int dep,int l,int r,int ql,int qr,int k) { if(l>=r)return tree[dep][l]; int mid=(l+r)>>1,s,ss; if(l!=ql) s=num[dep][ql-1],ss=num[dep][qr]-num[dep][ql-1];//s表示ql之前放在左边的个数,ss表示ql到qr这个区间内放在左边的个数; else s=0,ss=num[dep][qr]; if(k<=ss)return query(dep+1,l,mid,l+s,l+s+ss-1,k);//如果放在左边的个数就>=k,说明第k个数肯定在左边,右边就不用考虑了; else return query(dep+1,mid+1,r,mid+1+ql-l-s,mid+1+qr-l-s-ss,k-ss);//否则就在右边区间找第k个数; } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sorted[i]=tree[0][i]=a[i]; } sort(sorted+1,sorted+n+1); build(0,1,n); int l,r; for(int i=0;i<m;i++) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",query(0,1,n,l,r,k)); } } return 0; }