[NEERC 2004] K小数

  主席树模板。

  注意内存,每次 insert 会增加 log2n<<1 个节点,初始化线段树有 n<<2 个节点。

  总结点数 = ( n<<2 ) + ( n * log2n<<1 )。

  C++没有计算 log2() 的函数,但提供了 log10(),根据换底公式 log2n = log10n / log102。

// q.c

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int M=100000+10;
/************************************************************************/
int cnt,lc[M<<5],rc[M<<5],s[M<<5],L[M<<5],R[M<<5];
void build(int &o,int l,int r) {
	if(!o) o=++cnt; L[o]=l,R[o]=r;
	if(l==r) return ;
	int mid=(l+r)>>1;
	build(lc[o],l,mid),build(rc[o],mid+1,r);
}
void cpy(int x,int y) {
	lc[x]=lc[y],rc[x]=rc[y],s[x]=s[y],L[x]=L[y],R[x]=R[y];
}
void UP(int o) {
	s[o]=s[lc[o]]+s[rc[o]];
}
void insert(int &o,int p,int x) {
	if(!o) o=++cnt; cpy(o,p);
	if(L[o]==R[o]) { s[o]++; return ; }
	int mid=(L[o]+R[o])>>1;
	if(x<=mid) lc[o]=0,insert(lc[o],lc[p],x);
	else rc[o]=0,insert(rc[o],rc[p],x); UP(o);
}
int query(int o,int p,int k) {
	if(L[o]==R[o]) return L[o];
	int tmp=s[lc[o]]-s[lc[p]];
	if(k<=tmp) return query(lc[o],lc[p],k);
	else return query(rc[o],rc[p],k-tmp);
}
/************************************************************************/
struct Data {
	int x,y;
	bool operator < (const Data &A) const {
		if(x!=A.x) return x<A.x;
		return y<A.y;
	}
}w[M];
/************************************************************************/
int tot,v[M],res[M],root[M];
int main() {
	freopen("kthnumber.in","r",stdin);
	freopen("kthnumber.out","w",stdout);
	int n,m,a,b,c;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&w[i].x),w[i].y=i;
	sort(w+1,w+n+1);
	for(int i=1;i<=n;i++) {
		if(w[i].x!=w[i-1].x) v[w[i].y]=++tot,res[tot]=w[i].x;
		else v[w[i].y]=tot;
	}
	build(root[0],1,tot);
	for(int i=1;i<=n;i++) {
		insert(root[i],root[i-1],v[i]);
	}
	for(int i=1;i<=m;i++) {
		scanf("%d%d%d",&a,&b,&c);
		printf("%d\n",res[query(root[b],root[a-1],c)]);
	}
	return 0;
}

 

posted @ 2018-04-21 10:09  qjs12  阅读(118)  评论(0编辑  收藏  举报