好像又可以叫函数式线段树,反正主要思想就是充分利用历史信息,共用空间,具体的看论文吧
这里讲的比较详细
http://hi.baidu.com/wyl8899/item/e00796a9cb2df73d020a4d68
这题A的太爽了* _ *
看CLJ标称的时候用的是动态申请内存的线段树,非常不习惯- -
昨天听说可以静态实现,而且很简单,于是重新想了下实现的思路,果断开敲,敲之前把各种细节,包括如何调试都想的比较清楚,然后实现起来真的是有如行云流水,呵呵,有一种新的想法,然后通过不断的实践去实现它,这种感觉真好啊
好了,就献上我的代码吧,我写线段树就是懒得开结构体。。。
注:原先写的代码有个bug,poj数据太水,被我过了,在hdu wa了,现在已经修正
献上能在hdu AC的代码
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 100010; int ls[maxn*20],rs[maxn*20],sum[maxn*20]; int T[maxn],tot,rt; void build(int l,int r,int &rt) { rt=++tot; sum[rt]=0; if(l==r) return ; int m=l+r>>1; build(l,m,ls[rt]); build(m+1,r,rs[rt]); } void update(int last,int p,int l,int r,int &rt) { rt=++tot; ls[rt] = ls[last]; rs[rt] = rs[last]; sum[rt] = sum[last] + 1; if(l==r) return ; int m=l+r>>1; if(p<=m) update(ls[last],p,l,m,ls[rt]); else update(rs[last],p,m+1,r,rs[rt]); } int query(int ss,int tt,int l,int r,int k) { if(l==r) return l; int m=l+r>>1; int cnt=sum[ls[tt]] - sum[ls[ss]]; if(k <= cnt) return query(ls[ss],ls[tt],l,m,k); else return query(rs[ss],rs[tt],m+1,r,k-cnt); } int num[maxn],san[maxn],n,m; void gogogo() { int l,r,k; for(int i=1;i<=n;i++) { scanf("%d",&num[i]); san[i]=num[i]; } tot=0; sort(san+1,san+n+1); int cnt=unique(san+1,san+n+1)-san-1; build(1,cnt,T[0]); for(int i=1;i<=n;i++) num[i]=lower_bound(san+1,san+cnt+1,num[i])-san; for(int i=1;i<=n;i++) update(T[i-1],num[i],1,cnt,T[i]); while(m--) { scanf("%d%d%d",&l,&r,&k); int id=query(T[l-1],T[r],1,cnt,k); printf("%d\n",san[id]); } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); gogogo(); } return 0; }