第k元素log(n)算法–划分树
找第k小元素~什么划分树。很巧妙。
划分树神马的~algorithm:d[i][j]第i层的第j个排第几名。s[i][j]第i层的第j个之前包括第j个有多少个被分到左孩子。buildtree()像线段树那样建树。find()函数就可以找出x-y中第z名排第几名。有了s函数一切都好办了。
#include<iostream>
#include<cstdio>
using namespace std;
struct node{
int x,y;
};
node a[20000];
int d[20][100000],s[20][100000],n,m,x,y,z;
bool cmp(const node a,const node b)
{
return a.x<b.x;
}
void buildtree(int h,int l ,int r)
{
if (l==r) return;
int mid=(l+r)>>1,p=0;
for (int i=l;i<=r;++i)
{
if (d[h][i]<=mid)
{
d[h+1][l+p]=d[h][i];
++p;s[h][i]=p;
} else
{
d[h+1][mid+1+i-l-p]=d[h][i];
s[h][i]=p;
}
}
buildtree(h+1,l,mid);
buildtree(h+1,mid+1,r);
}
int find(int h,int l,int r,int ll,int rr,int k)
{
if (ll==rr) return (d[h][ll]);
int ls=0,rs=0;
if (ll>l) ls=s[h][ll-1];rs=s[h][rr];
if (rs-ls>=k) return find(h+1,l,(l+r)>>1,l+ls,l+rs-1,k);
else return find(h+1,((l+r)>>1)+1,r,((l+r)>>1)+1+ll-l-ls,((l+r)>>1)+rr-l+1-rs,k-(rs-ls));
}
int main()
{
freopen("350.in","r",stdin);
freopen("350.out","w",stdout);
cin>>n>>m;
for (int i=1;i<=n;++i)
{
cin>>a[i].x;a[i].y=i;
}
sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;++i) d[0][a[i].y]=i;
buildtree(0,1,n);
for (int i=1;i<=m;++i)
{
cin>>x>>y>>z;
cout<<a[find(0,1,n,x,y,z)].x<<endl;
}
return 0;
}
Knowledge make me stronger!