您的位置:首页 > 其它

POJ 2104 静态找区间第k大

2015-08-27 10:32 267 查看
静态区间第k大的问题,往往可以利用主席树来解决

这是主席树的第一道题

主席树大概可以理解为在n个节点上都建立一棵线段树,但是想想会超出内存

每一个节点保存的线段树都记录当前整段前缀区间的信息

但是因为每次添加后一个节点,那么他除了当前节点位置需要更新之外,其他的位置都可以保持跟上一棵节点对应的线段树一致,那么为了缩小内存,

将那些不需要改变的点的指针指向上一棵树对应的节点即可,其他多生成的节点也就是需要更新的节点,最多不超过log2n个,所以最后产生的线段树的

点的个数大概在nlogn的大致范围内

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define N 100005
#define M int m=(l+r)>>1
#define LS(o) node[o].ls
#define RS(o) node[o].rs

int n , m , a
, b
, T
;

struct Node{
int sz , ls , rs;
void init(){sz=0;ls=rs=0;}
}node[N*30];

int tot;

int build(int l , int r)
{
int u = tot++;
node[u].init();
if(l!=r){
M;
node[u].ls = build(l , m);
node[u].rs = build(m+1 , r);
}
return u;
}

void build(int o1 , int o2 , int l , int r , int pos)
{
node[o2].init();
node[o2].sz = node[o1].sz+1;
M;
if(l == r) return;
if(pos<=m){
node[o2].ls = tot++ , node[o2].rs = RS(o1);
build(LS(o1) , LS(o2) , l , m , pos);
}
else {
node[o2].rs = tot++ , node[o2].ls = LS(o1);
build(RS(o1) , RS(o2) , m+1 , r , pos);
}
}

int query(int o1 , int o2 , int l , int r , int k)
{
if(l==r) return l;
M;
int tmp;
if((tmp=node[LS(o2)].sz - node[LS(o1)].sz)>=k) return query(LS(o1) , LS(o2) , l , m , k);
else return query(RS(o1) , RS(o2) , m+1 , r , k-tmp);
}

int main()
{
// freopen("in.txt" , "r" , stdin);
while(~scanf("%d%d" , &n , &m)){
for(int i=1 ; i<=n ; i++)scanf("%d" , a+i);
for(int i=1 ; i<=n ; i++)b[i]=a[i];
sort(b+1 , b+n+1);
tot = 0;
T[0] = build(1 , n);
for(int i=1 ; i<=n ; i++){
int pos = lower_bound(b+1 , b+n+1 , a[i])-b;
T[i] = tot++;
build(T[i-1] , T[i] , 1 , n , pos);
}
while(m--){
int s , t , k;
scanf("%d%d%d" , &s , &t , &k);
int pos = query(T[s-1] , T[t] , 1 , n , k);
printf("%d\n" , b[pos]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: