初學樹剖的一些理解

2021-07-31 04:59:52 字數 2654 閱讀 9441

字面上來說,樹鏈,是樹上的路徑;剖分,就是把路徑分類為重鏈和輕鏈。

我們設乙個節點u的兒子為x1,x2,x3...,以這些兒子為根的子樹中節點個數(設為size)最多的是size[xi],則xi

是u的重兒子,u的其他兒子為輕兒子。

重邊:點u與其重兒子的連邊。

輕邊:點u與其輕兒子的連邊。

重鏈:由重邊連成的路徑。

輕鏈:由輕邊連成的路徑。

重鏈輕鏈的基本性質:

(1)輕邊(u,v)中,size(v)<=size(u)/2

(2)從根到某一點的路徑上,輕鏈、重鏈的個數都不大於logn。

假如設乙個點u所在重鏈的最頂端的點為top[u],另乙個點v所在重鏈的最頂端的點為top[v],當top[u]==top[v]時,一定有u為v的祖先或v為u的祖先。那麼如果在預處理的時候把top和dep都求出來,那麼就可以用重鏈u和v求lca——先判斷top[u]、top[v]是否相等,若不相等就判斷dep[top[u]]、dep[top[v]]大小關係,假若dep[top[u]]>=dep[top[v]],那麼u=fa[top[u]](dep[top[v]]>=dep[top[u]]時同理),然後繼續判斷top[u]、top[v]是否相等,直到相等後就可以直接比較dep求得lca(感覺並不能比一般的倍增快,但是樹剖要用此種方式)

下圖中加粗的就是重鏈,加紅點的就是每條重鏈的top(注意5、12、8、10):

要按照什麼順序把樹的邊或點放進線段樹呢?又和重鏈輕鏈有什麼關係呢?

上圖中排的順序就是:

id:       1   2   3   4   5   6   7   8   9   10   11   12   13   14

點的編號: 1   4   9   13  14  8   10  3   7   2    6    11   12   6

其實樹剖不一定把重兒子做特殊的兒子,根據不同的題目,可以是不同的。

**如下:題目鏈結(洛谷)

//serene

#include#include#include#include#include#includeusing namespace std;

const int maxn=100000+10;

long long n,m,root,mod,ans,val[maxn];

long long size[maxn],son[maxn],dep[maxn],fa[maxn];//son重兒子

long long aa;char cc;

long long read()

int to[2*maxn],fir[maxn],nxt[2*maxn],e=0;

void lianjie(int x,int y)

//求fa、size、son

void dfs1(int pos,int f,int d)

}//求id、top、end。end[i]表示以i為根的子樹的最後乙個id

long long id[maxn],top[maxn],v[maxn],end[maxn],num=0;

void dfs2(int pos,int t)

}struct treetree[4*maxn];

void bld(int pos,int l,int r)

int mid=(l+r)>>1;

bld(pos<<1,l,mid);bld(pos<<1|1,mid+1,r);

tree[pos].num=(tree[pos<<1].num+tree[pos<<1|1].num)%mod;

}long long query(int pos,int l,int r)

tree[pos].num=(tree[pos].num+tree[pos].laz*(tree[pos].r-tree[pos].l+1))%mod;

tree[pos].laz=0;

} if(tree[pos].l==l&&tree[pos].r==r) return tree[pos].num;

int mid=(tree[pos].l+tree[pos].r)>>1;

if(r<=mid) return query(pos<<1,l,r);

if(l>mid) return query(pos<<1|1,l,r);

return (query(pos<<1,l,mid)+query(pos<<1|1,mid+1,r))%mod;

}void chge(int pos,int l,int r,int x)

return;

} int mid=(tree[pos].l+tree[pos].r)>>1;

if(r<=mid) chge(pos<<1,l,r,x);

else if(l>mid) chge(pos<<1|1,l,r,x);

else chge(pos<<1,l,mid,x),chge(pos<<1|1,mid+1,r,x);

}//在求lca的過程中更新答案

void yth(int x,int y,int z) {

int tp1=top[x],tp2=top[y];

while(tp1!=tp2) {

if(dep[tp1]

樹鏈剖分的一些總結(TO DO)

樹鏈剖分的核心思想就是將乙個樹上問題轉化為鏈上問題,然後就可以用線段樹解決啦。這裡有乙個重鏈和輕鏈的概念。找到每個節點的重兒子作為他的son存下來。將每個點和他的重兒子們作為一條鏈搞下去。include using namespace std const int maxn 400005 int n,...

初學Linux的一些理解及簡單介紹

1 本週工作 學習關於linux 的知識。安裝 linux 系統,基本指令學習,遠端登入伺服器 2 學習總結 1 簡介 由於搭建hadoop 需要,這周安裝了 linux 系統。由於系統的特殊性,他的很大一部分的操作都是由命令組成的,因此必須要學習一些命令,linux 的許可權管理很是嚴格,所以,r...

關於初學者對於docker的一些。。理解

有錯希望指正。我的目的 能一鍵部署需要的服務和功能 現在有了目的。其實是朋友告訴我這東西可以快速部署環境覺得比我那樣一次次搞方便 然後我就是乙個0基礎的小白新手了。反正我也是剛剛畢業需要學習這些東西雖然公司只是傳統行業用不上。但是總會跳到我想要的網際網路環境的。首先,我知道了docker的映象每次啟...