poj2104
今天研究了一下函数式线段树(主席树),感觉很厉害呀!
主席树,其意义是对每序列中每个元素都建一棵子树,来描述前i个元素的信息
直接建树的话,时间、空间都是 N∗N∗logN ,肯定会MLE/TLE
记
Tree(i)
为描述
1
~
Tree(i)
与
Tree(i−1)
会有很多公共的信息,所以只有
logN
条新增信息
所以建树
Tree(i)
时,可以和
Tree(i−1)
共用一些节点,其余只需新增
logN
个节点
初始化 Tree(0) :建一棵空树
时间复杂度
O(N∗logN)
空间复杂度
O(N∗logN)
主席树空间计算: SIZE=N∗logN+3∗N
具体参见fhq神犇的:《范浩强_wc2012谈谈各种数据结构》
对于这个题,我除了写主席树就没动什么脑子,线段树代码直接敲,有些乱搞倾向。。。
tree(i)描述整个序列中 1~i小的元素在树中的分布情况
然后二分答案, l 和 r ,满足 count[i,j,tree(l)]<k<=count[i,j,tree(r)]
最后结果: ans=value(r) ,其实还是写长了。。。
时间复杂度( N∗logN+M∗logN )
较简易的代码实现: http://blog.csdn.net/q775968375 Orz
UPD:^_^,然而,最后我发现,我的主席树映射写反了233333,难怪代码这么长。。。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<math.h>
#define SIZE 2000000
#define MAXN 100005
int n,m;
struct node{int l,r,c[2],cnt;}mp[SIZE]={0};
int ml=0,root[MAXN]={0};
int a[MAXN]={0},rank[MAXN]={0},v[MAXN]={0},swap;
int ll,rr,ki;
int buildtree0(int l0,int r0)
{
int ret=++ml,mid=(l0+r0)>>1;
mp[ret].l=l0,mp[ret].r=r0;
if(l0==r0)return ret;
if(l0<=mid) mp[ret].c[0]=buildtree0(l0,mid);
if(mid+1<=r0)mp[ret].c[1]=buildtree0(mid+1,r0);
return ret;
}
int buildtree(int rt,int xi)
{
int mid=(mp[rt].l+mp[rt].r)>>1;
int ret=++ml,tag;
mp[ret].l=mp[rt].l;
mp[ret].r=mp[rt].r;
if(mp[rt].l==mp[rt].r)
{
mp[ret].c[0]=mp[ret].c[1]=0;
mp[ret].cnt=1;
return ret;
}
/*
if(xi<=mid)
{
mp[ret].c[0]=buildtree(mp[rt].c[0],xi);
mp[ret].c[1]=mp[rt].c[1];
}
else
{
mp[ret].c[0]=mp[rt].c[0];
mp[ret].c[1]=buildtree(mp[rt].c[1],xi);
}
*/
tag=(xi<=mid);
mp[ret].c[tag]=mp[rt].c[tag];
mp[ret].c[tag^1]=buildtree(mp[rt].c[tag^1],xi);
mp[ret].cnt=mp[mp[ret].c[0]].cnt+mp[mp[ret].c[1]].cnt;
return ret;
}
void sort(int l,int r)
{
int i=l,j=r;
int t=a[rank[l+rand()%(r-l+1)]];
while(i<=j)
{
while(a[rank[i]]<t)i++;
while(a[rank[j]]>t)j--;
if(i<=j)
{
swap=rank[i];
rank[i]=rank[j];
rank[j]=swap;
i++,j--;
}
}
if(l<j)sort(l,j);
if(i<r)sort(i,r);
}
int count(int s,int l,int r)
{
int mid=(mp[s].l+mp[s].r)>>1;
if(mp[s].l==l && mp[s].r==r)return mp[s].cnt;
if(r<=mid)
{
return count(mp[s].c[0],l,r);
}
else if(l>=mid+1)
{
return count(mp[s].c[1],l,r);
}
else
{
return count(mp[s].c[0],l,mid)+count(mp[s].c[1],mid+1,r);
}
}
int getnum();
int main()
{
int i,l,r,mid;
#ifndef ONLINE_JUDGE
freopen("poj2104.in","r",stdin);
freopen("poj2104.out","w",stdout);
#endif
srand(time(NULL));
n=getnum();m=getnum();
for(i=1;i<=n;i++)
rank[i]=i,a[i]=getnum();
if(n!=1)sort(1,n);
for(i=1;i<=n;i++)
{
v[rank[i]]=i;
}
root[0]=buildtree0(1,n);
for(i=1;i<=n;i++)
{
root[i]=buildtree(root[i-1],rank[i]);
}
while(m--)
{
ll=getnum();
rr=getnum();
ki=getnum();
l=1;r=n;
if(count(root[l],ll,rr)>=ki)
printf("%d\n",a[rank[l]]);
else
{
while(l+1!=r)
{
mid=(l+r)>>1;
if(count(root[mid],ll,rr)>=ki)
r=mid;
else
l=mid;
}
printf("%d\n",a[rank[r]]);
}
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
return 0;
}
char str[20],sl;int gi,gret,cq;
int getnum()
{
gret=0;
scanf("%s",str);
sl=strlen(str);
if(str[0]=='-')cq=-1,gi=1;
else cq=1,gi=0;
for(;gi<sl;gi++)
{
gret*=10;
gret+=str[gi]-'0';
}
return gret*cq;
}