题目链接:http://poj.org/problem?id=2104
题意:给出一个数列,若干询问L,R,K,询问区间[L,R]之间的第K小的数。
思路:划分树,函数式线段树
//划分树
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAX=100005;
struct Node
{
int L,R;
};
struct HuaFen_tree
{
Node a[MAX<<2];
int s[MAX],t[35][MAX],tot[35][MAX];
void input(int n)
{
int i;
for(i=1;i<=n;i++)
{
scanf("%d",&s[i]);
t[1][i]=s[i];
}
sort(s+1,s+n+1);
}
void build(int dep,int u,int L,int R)
{
a[u].L=L;
a[u].R=R;
if(L==R) return;
int i,mid=(L+R)>>1;
int sameNum=mid-L+1;
for(i=L;i<=R;i++) if(t[dep][i]<s[mid]) sameNum--;
int LL=L,LR=mid,RL=mid+1,RR=R;
int Lnum=0,Rnum=0;
for(i=L;i<=R;i++)
{
if(i==L) tot[dep][i]=0;
else tot[dep][i]=tot[dep][i-1];
if(t[dep][i]<s[mid])
{
tot[dep][i]++;
t[dep+1][LL+Lnum]=t[dep][i];
Lnum++;
}
else if(t[dep][i]>s[mid])
{
t[dep+1][RL+Rnum]=t[dep][i];
Rnum++;
}
else
{
if(sameNum>0)
{
sameNum--;
tot[dep][i]++;
t[dep+1][LL+Lnum]=t[dep][i];
Lnum++;
}
else
{
t[dep+1][RL+Rnum]=t[dep][i];
Rnum++;
}
}
}
build(dep+1,u<<1,LL,LR);
build(dep+1,u<<1|1,RL,RR);
}
//在区间[a[u].L,a[u].R]这个区间中查找[L,R]中的第K大值
int query(int dep,int u,int L,int R,int K)
{
if(L==R) return t[dep][L];
int x,y,xx,yy,_L,_R,mid=(a[u].L+a[u].R)>>1;
if(L==a[u].L) x=0;
else x=tot[dep][L-1]; //x为[a[u].L,L-1]中分到左边的
y=tot[dep][R]-x; //y为[L,R]中分到左边的
if(y>=K)
{
_L=a[u].L+x;
_R=a[u].L+x+y-1;
return query(dep+1,u<<1,_L,_R,K);
}
else
{
xx=L-a[u].L-x; //xx是[a[u].L,L-1]中分到右边的
yy=R-L+1-y; //yy是[L,R]中分到右边的
_L=mid+1+xx;
_R=mid+1+xx+yy-1;
return query(dep+1,u<<1|1,_L,_R,K-y);
}
}
};
HuaFen_tree a;
int n,m;
int main()
{
while(scanf("%d%d",&n,&m)!=-1)
{
a.input(n);
a.build(1,1,1,n);
int ans,L,R,K;
while(m--)
{
scanf("%d%d%d",&L,&R,&K);
ans=a.query(1,1,L,R,K);
printf("%d\n",ans);
}
}
return 0;
}
//函数式线段树
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
struct node
{
int a,b,L,R,s,mid;
};
const int MAX=3000000;
const int M=100005;
node t[MAX];
int root[M],tot;
int p[M],q[M],n,m;
int find(int low,int high,int p[],int key)
{
int mid;
while(low<=high)
{
mid=(low+high)>>1;
if(p[mid]==key) break;
if(p[mid]>key) high=mid-1;
else low=mid+1;
}
return mid;
}
int build(int a,int b)
{
int k=++tot;
t[k].a=a;
t[k].b=b;
t[k].s=0;
t[k].mid=(a+b)/2;
if(a!=b)
{
t[k].L=build(a,t[k].mid);
t[k].R=build(t[k].mid+1,b);
}
return k;
}
int change(int p,int x,int s)
{
int k=++tot;
t[k]=t[p];
t[k].s+=s;
if(t[k].a==x&&t[k].b==x) return k;
if(x<=t[k].mid) t[k].L=change(t[p].L,x,s);
else t[k].R=change(t[p].R,x,s);
return k;
}
int query(int p,int q,int k)
{
if(t[q].a==t[q].b) return t[q].a;
int x=t[t[q].L].s-t[t[p].L].s;
if(k<=x) return query(t[p].L,t[q].L,k);
return query(t[p].R,t[q].R,k-x);
}
int main()
{
while(scanf("%d%d",&n,&m)!=-1)
{
tot=0;
int i,k;
for(i=1;i<=n;i++)
{
scanf("%d",p+i);
q[i]=p[i];
}
sort(q+1,q+n+1);
k=unique(q+1,q+n+1)-(q+1);
for(i=1;i<=n;i++) p[i]=find(1,k,q,p[i]);
root[0]=build(1,k);
for(i=1;i<=n;i++) root[i]=change(root[i-1],p[i],1);
int L,R;
while(m--)
{
scanf("%d%d%d",&L,&R,&k);
printf("%d\n",q[query(root[L-1],root[R],k)]);
}
}
return 0;
}