洛谷P3402 【模板】可持久化並查集(可持久化線段樹,線段樹)
阿新 • • 發佈:2018-02-06
std 樹節點 https case 深度 build eof spa 復雜度 的,但空間也是O\((Mlog^2N)\)的啊,乘個系數\((Mlog^2N×sizeof(int)×4\approx 800MB\),實際不滿\()\),隨便算算就要炸空間了。。。。。。
orz TPLY 巨佬,題解講的挺好的。
這裏重點梳理一下思路,做一個小小的補充吧。
寫可持久化線段樹,葉子節點維護每個位置的fa,利用每次只更新一個節點的特性,每次插入\(logN\)個節點,這一部分思路還是很輕松。關於此部分的其它問題可以參考下我的可持久化線段樹總結
一開始,寫慣了常規並查集、用慣了路徑壓縮的我,以為在這一題裏也要這麽搞。我對我的naive真是太感動了
試想一下,因為路徑壓縮時,再次調用getf後,是要更新一部分值的。在數組上搞這些操作倒是挺快,然而在可持久化線段樹裏呢?每次找一個fa要\(log\)次,把這個節點更新又要新建log個節點,一共要循環找不滿log次,理論上時間復雜度是\(O(Mlog^2N)\)
那怎麽辦?去掉路徑壓縮不就得啦!並查集的按秩合並也是很優秀的方法,每次getf也只需要\(log\)次!時間復雜度\(O(Mlog^2N)\)並沒有變。然後每次合並時只需要更新一個點,空間不就省下來了麽?空間復雜度\(O(MlogN)\)。
以下是代碼,數組版,葉子節點信息用結構體放了一下,略省點空間吧。。。
太弱了,不會封裝,非遞歸版,可能略醜,見諒
#include<cstdio> #define R register int #define gc while(*++p<‘0‘) #define in(z) gc;z=*p&15;while(*++p>=‘0‘)z*=10,z+=*p&15 #define copy(id) lc[rt[i]=++cnt]=lc[rt[id]],rc[cnt]=rc[rt[id]]; //直接復制版本,不做改動 const int N=200009,M=4000009; char I[M]; int n,i,cnt,cntl,rt[N],lc[M],rc[M],pos[M]; //cnt線段樹節點,cntl葉子節點,pos記錄對應葉子節點在數組中的位置 struct LEAF{ int fa,dep; }leaf[N<<2];//葉子節點信息,dep用於按秩合並 inline LEAF*getf(R k){ R u,l,r,m; while(1){ u=rt[i-1],l=1,r=n; while(l<r) { m=(l+r)>>1; if(k<=m)r=m,u=lc[u]; else l=m+1,u=rc[u]; } if(k==leaf[pos[u]].fa)break; k=leaf[pos[u]].fa;//循環找fa } return&leaf[pos[u]];//返回指針方便後續操作 } void build(R&u,R l,R r){//建初始線段樹 u=++cnt; if(l==r){ leaf[pos[u]=++cntl]=(LEAF){l,0}; return; } R m=(l+r)>>1; build(lc[u],l,m),build(rc[u],m+1,r); } inline void insert(R*u,R v,R k,LEAF newl){//更新節點 R l=1,r=n,m; while(l<r) { *u=++cnt; m=(l+r)>>1; if(k<=m)r=m,rc[*u]=rc[v],u=&lc[*u],v=lc[v]; else l=m+1,lc[*u]=lc[v],u=&rc[*u],v=rc[v]; } leaf[pos[*u=++cnt]=++cntl]=newl; } int main(){ fread(I,1,sizeof(I),stdin); register char*p=I-1; register LEAF*af,*bf,*tmp; R m,a,b; in(n);in(m); build(rt[0],1,n); for(i=1;i<=m;++i){ gc; switch(*p){ case ‘1‘:in(a);in(b); af=getf(a),bf=getf(b); if(af->fa==bf->fa){copy(i-1);break;}//已合並,跳過操作 if(af->dep>bf->dep)tmp=af,af=bf,bf=tmp;//按秩合並,確定bf為深度更大的 insert(&rt[i],rt[i-1],af->fa,(LEAF){bf->fa,af->dep}); if(af->dep==bf->dep)insert(&rt[i],rt[i],bf->fa,(LEAF){bf->fa,bf->dep+1});//註意更新深度 break; case ‘2‘:in(a);copy(a);break; case ‘3‘:in(a);in(b);copy(i-1); putchar((getf(a)->fa==getf(b)->fa)|‘0‘); putchar(‘\n‘); } } return 0; }
洛谷P3402 【模板】可持久化並查集(可持久化線段樹,線段樹)