1. 程式人生 > >關於樹論【主席樹】

關於樹論【主席樹】

實現 main 可能 += while 然而 truct node 現在

很後悔之前在XGC大佬講的時候沒認真聽(其實講的不q不c,幸好了解了一下),現在搞搞差不多理解了。

這個東西是線段樹的進化版,強大在於實現了可持久化,後一刻可以參考前一刻的狀態。
裸題:給n(1<=n<=100000)個數字a[1],a[2],......,a[n](0<=a[i]<=1000000000),m(1<=m<=100000)次詢問l到r之間的第k小的值。
對於這種頻繁詢問l~r的第k小,線段樹原地爆炸。

所以說要用主席樹。
首先對於線段樹的定義有一點不同(線段樹求他的最小值應該是按數列位置排,管理的點有個mn記錄區間最小),而在主席樹,他的葉子節點是記錄這個區間有多少個這個數,舉個例子,比如數列裏有3個1,那管理1~1的點c值為3,然後回溯更新父親,所以說,為了防止讀入的數值太大以至於爆內存,所以說要離散化。


對於這個序列每一個前綴,都為他建一棵新樹,這個數列管理1~i的值,然而不用想就知道,建這麽多樹不爆才怪,那怎麽辦?可以發現,管理1~i-1和管理1~i的樹只差一個點,而a[i]只會影響到從葉子節點到根一條路徑的值,那這兩棵樹就可以共用不影響的點,達到省空間的目的。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
    int lc,rc,c;
}tr[2100000
];int cnt; int a[110000],b[110000],rt[110000]; int maketree(int x,int l,int r,int p) { if(x==0)x=++cnt;tr[x].c++;//開新點,然後管理的人數++ if(l==r)return x; int mid=(l+r)/2; if(p<=mid)tr[x].lc=maketree(tr[x].lc,l,mid,p);//a[i]應該隸屬那個子樹 else tr[x].rc=maketree(tr[x].rc,mid+1,r,p); return
x; } int Merge(int x,int y) { if(x==0||y==0)return x+y;//假如說x沒有這個節點,而y有,那就不用開新點,直接連過去,也就是說一個的點有可能多個父親 tr[x].c+=tr[y].c;//x的總人數加上y的 tr[x].lc=Merge(tr[x].lc,tr[y].lc); tr[x].rc=Merge(tr[x].rc,tr[y].rc); return x; } int findans(int x,int y,int l,int r,int k) { if(l==r)return b[l];//l是離散了的值,找回原來的 int c=tr[tr[x].lc].c-tr[tr[y].lc].c;//得出區間真正有的點數,就是前綴和的應用 int mid=(l+r)/2; if(k<=c)return findans(tr[x].lc,tr[y].lc,l,mid,k); else return findans(tr[x].rc,tr[y].rc,mid+1,r,k-c); } int n,m; int erfen(int k)//二分實際是得出離散值,不然線段樹空間爆炸 { int l=1,r=n,mid,ans; while(l<=r) { mid=(l+r)/2; if(b[mid]<=k) { l=mid+1; ans=mid; } else r=mid-1; } return ans; } char ss[10]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); cnt=0;memset(rt,0,sizeof(rt)); for(int i=1;i<=n;i++) { rt[i]=maketree(rt[i],1,n,erfen(a[i]));//這棵樹裏就記錄了a[i] rt[i]=Merge(rt[i],rt[i-1]);//上一棵樹記錄a[1]~a[i-1],讓新的和這個合並一下(上一棵樹保留),就得到a[1]~a[i]了 } int x,y,k; while(m--) { scanf("%d%d%d",&x,&y,&k); printf("%d\n",findans(rt[y],rt[x-1],1,n,k));//類似求前綴和,主席樹就是按前綴建樹啊! } return 0; }

關於樹論【主席樹】