標籤:poj2104 k-th number 主席樹 函數式線段樹 可持久化線段樹
題意:區間靜態第K大。
題解:
可持久化線段樹。
可持久化線段樹:
基本思想:我們維護插入每個節點後的線段樹。
樸素寫法(MLE+TLE)我們對於每次插入,都複製一棵線段樹而後插入,這樣保證了“可持久化”。
但是顯然,時間複雜度和空間複雜度都是n^2的。233。
所以有了最佳化寫法:我們發現每次的插入只有logn個節點被改變,所以只需要這些點建立,其它點都指向原來版本的節點就好了。
空間複雜度nlogn。
然後這道題是區間第K大,對於區間[a,b],插入到b時的線段樹,節點的size-(a-1)時節點的size,顯然就是[a,b]這個區間中插入數值後的結果,根據這個可以進行查詢。
代碼太水了,不懂可以自己看代碼。
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 101000#define LOGN 20#define inf 0x3f3f3f3f#define ls s[x].son[0]#define rs s[x].son[1]using namespace std;int pos[N],n,m;int src[N],rank;int crs[N];struct LSH{int x,id;bool operator < (const LSH &a)const{return x<a.x;}}lsh[N];int cnt;struct Functional_Segment_Tree{int son[2];int size,l,r;}s[N*LOGN];inline void pushup(int x){s[x].size=s[ls].size+s[rs].size;}int build(int last,int l,int r,int d){int x=++cnt;s[x].size=s[last].size,s[x].l=l,s[x].r=r;if(l==r){s[x].size++;return x;}int mid=l+r>>1;if(d<=mid)ls=build(s[last].son[0],l,mid,d),rs=s[last].son[1];else rs=build(s[last].son[1],mid+1,r,d),ls=s[last].son[0];pushup(x);return x;}void query(int last,int now,int l,int r,int k){if(l==r){printf("%d\n",crs[l]);return ;}int mid=l+r>>1,temp=s[s[now].son[0]].size-s[s[last].son[0]].size;if(temp<k)query(s[last].son[1],s[now].son[1],mid+1,r,k-temp);else query(s[last].son[0],s[now].son[0],l,mid,k);}int main(){//freopen("test.in","r",stdin);int i,a,b,c;scanf("%d%d",&n,&m);for(i=1;i<=n;i++)scanf("%d",&lsh[i].x),lsh[i].id=i;sort(lsh+1,lsh+n+1);src[lsh[1].id]=++rank,crs[rank]=lsh[1].x;for(i=2;i<=n;i++){if(lsh[i].x!=lsh[i-1].x)crs[++rank]=lsh[i].x;src[lsh[i].id]=rank;}for(i=1;i<=n;i++)pos[i]=build(pos[i-1],1,rank,src[i]);while(m--){scanf("%d%d%d",&a,&b,&c);query(pos[a-1],pos[b],1,n,c);}return 0;}
【POJ2104】K-th Number 主席樹?函數式線段樹?可持久化線段樹?……反正是其中一個