题目:http://poj.org/problem?id=2104
划分树待我好好理解下再写个教程吧,觉得网上的内容一般,,,
模板题:
贴代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a) memset(a,0,sizeof(a))
const int MAXN = 100010;
struct Node
{
int l,r;
int len(){return r-l;}
int mid(){return (l+r)/2;}
bool in(int ll,int rr){return l>=ll && r<=rr;}
void lr(int ll,int rr){l = ll; r=rr;}
}node[MAXN*4];
int num_left[20][MAXN],seg[20][MAXN],sa[MAXN];
//sa数组存sort后的结果
//seg数组存的是d层划分后的数字 (类似快排Partation (d-1)次后的结果)
//num_left存的是d层在i之前(包括i)小于 sa[mid] 的数的数目
void Init()
{
//CLR(seg),CLR(num_left),CLR(node);
memset(seg,0,sizeof(seg));
memset(num_left,0,sizeof(num_left));
memset(node,0,sizeof(node));
}
void PaBuild(int t,int l, int r,int d)
{
node[t].lr(l,r);
if(node[t].len() == 0)return;
int mid=(l+r)/2,lsame=mid-l+1;
for(int i=l;i<=r;i++)//首先确定分到每一侧的数的数目
if(seg[d][i] < sa[mid])//因为相同的元素可能被分到两侧
lsame--;
int lpos=l,rpos=mid+1;
for(int i=l;i<=r;i++)
{
if(i == l)
num_left[d][i]=0;
else
num_left[d][i]=num_left[d][i-1];
if(seg[d][i] < sa[mid])
{
num_left[d][i]++;
seg[d+1][lpos++]=seg[d][i];
}
if(seg[d][i] > sa[mid])
seg[d+1][rpos++] = seg[d][i];
if(seg[d][i] == sa[mid])
if(lsame > 0)// 如果大于0,说明左侧可以分和sa[mid]相同的数字
{
lsame--;
num_left[d][i]++;
seg[d+1][lpos++]=seg[d][i];
}
else //反之,说明左侧数字已经分满了,就分到右边去
seg[d+1][rpos++]=seg[d][i];
}
PaBuild(t*2,l,mid,d+1);
PaBuild(t*2+1,mid+1,r,d+1);
}
void Build(int s,int t)
{
sort(sa+s,sa+t+s);
PaBuild(1,s,t,1);
}
int find_rank(int t,int l,int r,int d,int val)//val指的是k
{
if(node[t].len() == 0)return seg[d][l];
int s,ss; //s表示区间[l,r]有多少个小于sa[mid]的数被分到左边
if( l == node[t].l)//ss表示从当前区间的L到l-1有多少个小于sa[mid]的数被分到左边,L,R指的是树上当前节点的区间范围
ss=0;
else
ss=num_left[d][l-1];
s=num_left[d][r]-ss;
if(s>=val)
return find_rank(t*2, node[t].l+ss,node[t].l+ss+s-1,d+1,val);
else
{
int mid = node[t].mid();
int bb=l-node[t].l-ss; //表示从当前区间L到l-1有多少个分到右边
int b=r-l+1-s; //表示[l,r]有多少个分到右边
return find_rank(t*2+1,mid+bb+1,mid+bb+b,d+1,val-s);
}
}
int Query(int s,int t,int k)
{
return find_rank(1,s,t,1,k);
}
int main()
{
int n,m,x,y,k;
while(~scanf("%d%d",&n,&m))
{
Init();
for(int i=1;i<=n;i++)
{
scanf("%d",&sa[i]);
seg[1][i] = sa[i];
}
Build(1,n);
while(m--)
{
scanf("%d%d%d",&x,&y,&k);
int ans=Query(x,y,k);
printf("%d\n",ans);
}
}
return 0;
}