Time Limit: 20000MS | Memory Limit: 65536K | |
Total Submissions: 38927 | Accepted: 12663 | |
Case Time Limit: 2000MS |
Description
Input
Output
Sample Input
7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 7 3
Sample Output
5 6 3
Hint
Source
主席树求区间第k大,注释见代码。
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <cstdlib> #define maxn 100005 using namespace std; int b[maxn],t[maxn],n,m,size,v[maxn],tot=0; struct chairtree { int l,r,size; }a[maxn*30]; int Build(int l,int r) { int root=++tot; a[root].size=0; if (l==r) return root; int m=(l+r)>>1; a[root].l=Build(l,m); a[root].r=Build(m+1,r); return root; } int Update(int root,int x) { int now=++tot; int tmp=now; a[tot].size=a[root].size+1; int l=1,r=size; while (l<r) { int m=(l+r)>>1; if (x<=m) { a[now].l=++tot; a[now].r=a[root].r; //充分利用原来相同的结点 root=a[root].l; now=tot; r=m; } else { a[now].l=a[root].l; a[now].r=++tot; root=a[root].r; now=tot; l=m+1; } a[now].size=a[root].size+1; } return tmp; } int Ask(int lx,int rx,int k) { int l=1,r=size; while (l<r) { int m=(l+r)>>1; if (a[a[rx].l].size-a[a[lx].l].size>=k) { r=m; lx=a[lx].l; rx=a[rx].l; } else { l=m+1; k-=a[a[rx].l].size-a[a[lx].l].size; lx=a[lx].r; rx=a[rx].r; } } return l; } void Hash1() { sort(b+1,b+1+n); size=unique(b+1,b+1+n)-b-1; //求不相同的数有几个 } int Hash(int x) { return lower_bound(b+1,b+1+size,x)-b; //找到x在排好序的序列中出现的位置,即离散化后的值 } int main() { while (scanf("%d%d",&n,&m)==2) { for (int i=1;i<=n;i++) scanf("%d",&v[i]),b[i]=v[i]; Hash1(); t[0]=Build(1,size); for (int i=1;i<=n;i++) //建n棵线段树 t[i]=Update(t[i-1],Hash(v[i])); while (m--) { int l,r,k; scanf("%d%d%d",&l,&r,&k); printf("%d\n",b[Ask(t[l-1],t[r],k)]); } } return 0; }
注意:
1.unique函数中最后要-1,但还不知道原因。。以后再说。。
2.lower_bound中是+size而不是+all,记住。。