樹鏈剖分,是一種將樹剖分成多條不相交的鏈的演算法,並通過其他的資料結構來維護這些鏈上的資訊。
最簡單的例子就是\(lca\),假設現在有一棵退化成鏈的樹。如果要求任意兩點的\(lca\),因為他們在同一條鏈上的緣故,只需要判斷一下兩者的深度就行了。由此可見,在鏈上是比在樹上更好操作的。
那麼該怎麼將一棵樹剖分開來捏?
先搬出一堆概念:
重兒子
在以x節點為根的子樹中,節點數最多的子樹的根節點,即是x節點的重兒子。
重邊連線x節點與x節點的重兒子的邊,我們叫他重邊。
重鏈一堆重邊連起來的鏈。
輕鏈一堆非重邊連起來的鏈。
對於每個節點,找出其重兒子,就可以剖分成一條條重鏈與輕鏈。
陣列定義
\(dfs\)
第一遍\(dfs\)處理出\(size,fa,son,dep\)線段樹第二遍\(dfs\)處理出\(top,dfn,rk\)
用線段樹維護樹鏈,並實現鏈上的操作,常見操作如下:將樹從\(x\)到\(y\)結點最短路徑上所有節點的值都加上\(z\)
求樹從\(x\)到\(y\)結點最短路徑上所有節點的值之和
將以\(x\)為根節點的子樹內所有節點值都加上\(z\)
求以\(x\)為根節點的子樹內所有節點值之和
對於子樹操作:我們知道一顆子樹內的編號一定是連續的,那麼以\(x\)節點為根的子樹的區間就是\((dfn[x],dfn[x]+size[x]-1)\)
#define rg register
#include#includeusing namespace std;
const int n=1e5+5;
inline int read()
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}int n,m,r,p,cnt,ct;
int lazy[n<<2],sum[n<<2];
int val[n],size[n],son[n],fa[n],dfn[n],rk[n],last[n],dep[n],top[n];
struct edgee[n<<1];
void insert(int u,int v)
;last[u]=cnt;
e[++cnt]=(edge);last[v]=cnt;
}inline void dfs1(int now)
}inline void dfs2(int now,int top)
}inline void pushup(int root)
void build(int root,int l,int r)//建樹
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
pushup(root);
}inline void pushdown(int root,int len)//下放懶標記,len為區間長度
void modify(int root,int l,int r,int ll,int rr,int k)//區間修改
int mid=(l+r)>>1;
if(ll<=mid)modify(root<<1,l,mid,ll,rr,k);
if(rr>mid)modify(root<<1|1,mid+1,r,ll,rr,k);
pushup(root);
}int query(int root,int l,int r,int ll,int rr)//區間查詢
inline int query_tree(int x,int y)//查詢節點x到節點y路徑上點權和
inline void modify_son(int x,int k)//子樹修改
inline int query_son(int x)
int main()
if(f==2)printf("%d\n",query_tree(read(),read()));
if(f==3)
if(f==4)printf("%d\n",query_son(read()));
}return 0;
}
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 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...
演算法入門 樹鏈剖分 輕重鏈剖分
目錄 3.0 求 lca 4.0 利用資料結構維護資訊 5.0 例題 參考資料 資料結構入門 線段樹 發表於 2019 11 28 20 39 dfkuaid 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查詢 標記下傳 標記永久化 閱讀全文 樹鏈剖分用...
樹鏈剖分 樹剖換根
這是一道模板題。給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...