poj2104主席树
题意
给定一个数列,给出若干个询问(l,r,k),求出[l,r]区间内第k小的数。
做法
用若干棵线段树分别维护前缀Si的离散化后的该数的个数,即在某棵线段树中,第i个位置表示离散化后大小为i的元素的个数,查询时在线段树上进行二分。
代码
#include <cstdio>
#include <cstring>
#include <cstdlib>
class node{
public:
int l,r, sum;
node *linkl, *linkr;
};
const int nn=100005;
node* root[nn];
class node1{
public:
int x, num;
} a1[nn];
int a[nn];
int num;
int hash[nn];
int n,m;
void build(node *&p, int l, int r){
p=(node*)malloc(sizeof(node));
p->l = l; p->r = r; p->linkl = p->linkr = NULL;
if (l < r){
int mid = (l + r) >> 1;
build(p->linkl, l, mid);
build(p->linkr, mid+1, r);
p->sum = p->linkl->sum + p->linkr->sum;
} else{
p->sum = 0;
}
}
void build1(int x, node *&p, node *p1, int l,int r){
p=(node*)malloc(sizeof(node));
p->l = l; p->r = r;
p->linkl = p->linkr = NULL;
if (l < r) {
int mid = (l + r) >> 1;
if (x <= mid){
build1(x, p->linkl, p1->linkl, l, mid);
p->linkr = p1->linkr;
} else {
build1(x, p->linkr, p1->linkr, mid+1, r);
p->linkl = p1->linkl;
}
p->sum = p->linkl->sum + p->linkr->sum;
} else p->sum = p1->sum + 1;
}
inline int check(node *p1, node *p2, int k){
while (p1->l != p1->r){
if (k <= p2->linkl->sum - p1->linkl->sum) {
p2 = p2 -> linkl; p1 = p1 -> linkl;
} else{
k -= (p2 -> linkl->sum - p1->linkl->sum);
p2 = p2 -> linkr; p1 = p1 ->linkr;
}
}
return (p1->l);
}
int scan(){
char c;
int x(0);
bool f(false);
while(c=getchar(),c==' ' || c== '\n');
if (c == '-') {
f = true;
c = getchar();
}
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0';
if (f) x = 0 - x;
return x;
}
void qsort(int l, int r){
node1 mid=a1[(l + r) >> 1];
int i(l), j(r);
node1 t;
do{
while (a1[i].x < mid.x) ++i;
while (a1[j].x > mid.x) --j;
if (i <= j){
t = a1[i]; a1[i] = a1[j]; a1[j] = t;
++i; --j;
}
} while (i < j);
if (l < j) qsort(l, j);
if (i < r) qsort(i, r);
}
int main(){
freopen("poj2104.in", "r", stdin);
freopen("poj2104.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i=1;i<=n;++i){
a1[i].x = scan();
a1[i].num = i;
}
qsort(1, n);
a[a1[1].num] = 1;
hash[1] = a1[1].x;
num = 1;
for (int i=2;i<=n;++i){
if (a1[i].num != a1[i-1].num) ++num;
a[a1[i].num] = num;
hash[num] = a1[i].x;
}
build(root[0], 1, num);
for (int i=1;i<=num;++i) build1(a[i], root[i], root[i-1], 1, num);
int l,r,k;
for (int i=1;i<=m;++i){
l = scan(); r = scan(); k = scan();
printf("%d\n", hash[check(root[l-1], root[r], k)]);
}
fclose(stdin);
fclose(stdout);
return 0;
}