洛谷-樹鏈剖分模板
前置芝士:鏈式前向星,線段樹,dfs序
這裡寫的是重鏈剖分。
參考部落格指盜圖**: x正義小學生x
樹鏈剖分可以把一棵樹「投影「到乙個序列上,然後用線段樹維護一些東西。
通過重兒子的性質來保證時間複雜度。
我們首先使用兩次dfs進行預處理,將樹投影到序列上。
對於乙個有兒子的節點,我們定義它最大的兒子為重兒子。
圖中,3,6,10,5,8就是重兒子。
我們稱像1-3-6-10,2-5,4-8這樣的為一條重鏈。
顯然會形成很多條重鏈,每個點屬於且只屬於一條重鏈。
我們定義乙個陣列 \(top_x\) 表示 \(x\) 所在的重鏈的最淺節點。
在第一次dfs中,我們求出每個點的深度dep,父親節點fa,子樹大小sz,重兒子。
在第二次dfs中,我們求出每個點的dfs序(時間戳就是在新序列裡的位置),並且儲存新序列,建線段樹。注意要儲存每個樹上的點 對應在序列裡的位置 。稱為 \(id_x\)
預處理之後,就要對付詢問。
詢問和修改子樹很顯然,是詢問和修改序列 \([id[x],id[x]+sz[x]-1]\)
鏈怎麼辦呢?樹鏈剖分,意思是將鏈剖開成多個(一條重鏈 或者 一條重鏈的一部分)。
設鏈的兩頭為 \(x\) 和 \(y\) ,
務必注意update的時候兩點的位置!
void updrange(int x,int y,int z)
怎麼保證時間複雜度是
也就是說,根到乙個點最多 \(log n\) 條輕邊。
線段樹有乙隻log,剖鏈會剖成的條數也有乙隻log,一共兩隻log。
時間複雜度 \(o(nlog^2n)\)
#includeusing namespace std;
const int n=1e5+10;
typedef long long ll;
int n,m,r,p;
int e,to[n<<1],nxt[n<<1],hd[n];
int tim,sz[n],dep[n],fa[n],top[n],son[n],id[n];
ll stval[n],fnval[n];
struct post[n<<2];
void add(int a,int b)
void pushup(int rt)
void pushdown(int rt)
}void build(int rt,int l,int r)
int mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}void update(int rt,int l,int r,int l,int r,ll val)
pushdown(rt);
int mid=l+r>>1;
if(l<=mid) update(rt<<1,l,mid,l,r,val);
if(r>mid) update(rt<<1|1,mid+1,r,l,r,val);
pushup(rt);
}ll query(int rt,int l,int r,int l,int r)
void dfs1(int u,int fat)
return;
}//dep,fa,子樹大小(含它自己),重兒子編號son
void dfs2(int u,int topf)
return;
}//新編號,賦值到新編號上,所在鏈的頂端,處理每條鏈
void updrange(int x,int y,int z)
ll qrange(int x,int y)
void updson(int x,int z)
ll qson(int x)
int main()
dfs1(r,0); dfs2(r,r);
build(1,1,n);
for(int i=1,tp,x,y;i<=m;i++) else if(tp==2) else if(tp==3) else
}
return 0;
}
筆記 樹鏈剖分
樹鏈剖分 對於每個結點 連線子節點多的那個子樹的邊叫做重邊 重邊連起來成鏈 叫重鏈 不止是只有一條重鏈 使用線段樹或者其他的資料結構存重鏈 用此資料結構進行操作 兩個dfs操作 第乙個dfs 求出重鏈 深度dep陣列 父節點fa陣列 和每個結點的子結點個數size陣列 知道了size才可以求出重鏈 ...
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...
樹鏈剖分筆記 (戳)
對於樹鏈剖分,看到大佬紛紛各種躺切內心很是惶恐,於是跪著請教大佬之後把自己的一點感悟發出來以防以後忘了qwq 指一種對樹進行劃分的演算法,它先通過輕重邊剖分將樹分為多條鏈,保證每個點屬於且只屬於一條鏈,然後再通過資料結構 樹狀陣列 sbt splay 線段樹等 來維護每一條鏈 常見的剖分的方法是輕重...