可持久化線段樹
也叫函數式線段樹也叫主席樹,其主要思想是充分利用歷史信息,共用空間
http://blog.sina.com.cn/s/blog_4a0c4e5d0101c8fr.html
這個博客總結的挺好的!
區間k大數問題
對於沒有修改的版本,我們可以先離散化然后對權值建樹。
結點存儲的是該權值范圍內出現元素的總次數。
在線段樹上找k大數時就像平衡樹詢問k大數一樣根據結點上的信息往左或者往右走。
現在可以利用函數式線段樹維護權值出現數量,將數列中每個結點依次插入線段樹,
第r次插入后的線段樹與第l-1次插入的線段樹之“差”(對應結點的值相減,因為按權值建樹結構是一樣的)得到的線段樹里進行上述的查找k大數操作即可。
總之,對於點操作,新增加一個點或修改一個點,只要新建一條從這個點到root[i]的路徑即可,這樣就形成第i個歷史版本的線段樹
模板引自http://blog.csdn.net/crazy_ac/article/details/8033596
// File Name: 2104.cpp // Author: Zlbing // Created Time: 2013年10月06日 星期日 18時04分39秒 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=1e5+100; int ls[MAXN*20],rs[MAXN*20]; int sum[MAXN*20]; int root[MAXN]; //root表示N顆線段樹的根結點 int tot; 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],hash[MAXN]; int main() { int n,m; int cas; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); REP(i,1,n) { scanf("%d",&num[i]); hash[i]=num[i]; } tot=0; sort(hash+1,hash+n+1); int cnt=unique(hash+1,hash+n+1)-hash-1; build(1,cnt,root[0]); REP(i,1,n) { num[i]=lower_bound(hash+1,hash+cnt+1,num[i])-hash; } REP(i,1,n) { update(root[i-1],num[i],1,cnt,root[i]); } int a,b,c; REP(i,1,m) { scanf("%d%d%d",&a,&b,&c); int ans=query(root[a-1],root[b],1,cnt,c); printf("%d\n",hash[ans]); } } return 0; }