P3384 模板 樹鏈剖分

2022-03-16 15:29:56 字數 2791 閱讀 6985

樹鏈剖分 時間!!!!

首先要學會線段樹。由於線段樹是基本技能,所以不再此過多解釋。

樹鏈剖分操作如下

操作1: 格式: 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z

操作2: 格式: 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和

操作3: 格式: 3 x z 表示將以x為根節點的子樹內所有節點值都加上z

操作4: 格式: 4 x 表示求以x為根節點的子樹內所有節點值之和

還有幾個概念:重兒子,輕兒子,重鏈,輕鏈。

眾所周知,以每乙個節點為根節點下所成的樹(語文技能崩潰)都有乙個大小(節點的數量)

如果有乙個兒子體型(節點數)在所有兄弟姐妹中最大,那麼這個兒子就是這個節點的重兒子;

其他的兒子都是輕兒子。

重邊就是每兩個重兒子之間的邊(手拉手,我們都是重兒子);輕邊就是剩下的;

重鏈就是相鄰的每個重邊連起來的鏈,包括一條端點重兒子和輕兒子之間的邊,也就是所有重鏈以乙個輕兒子開始;

看完定義該幹事了!!!

首先,處理dep,fa,siz,son

void dfs1(int u,int

fa)}

second 新編,賦值,找頭,先重再輕

因為先處理重兒子就會讓重兒子之間的編號是連續的。

void dfs2(int u,int

tp)

}

third 套用線段樹。

**:

#include#include

#include

using

namespace

std;

const

int maxn=100050

;int

n,m,s,mo,a[maxn];

int pre[maxn*2],other[maxn*2

],last[maxn],l;

intf[maxn],siz[maxn],dep[maxn],son[maxn];

intid[maxn],cnt,top[maxn],b[maxn];

void add(int x,int

y)//

下面是線段樹

struct

tree

t[4*maxn];//

四倍,前人的經驗

void build(int x,int l,int r)//

建樹

int mid=(l+r)>>1

; build(

2*x,l,mid);

build(

2*x+1,mid+1

,r);

t[x].sum=(t[2*x].sum+t[2*x+1].sum)%mo;

}void update(int x)//

更新懶標籤

void change(int x,int l,int r,int z)//

改變值

if(t[x].lazy) update(x);

int mid=(t[x].l+t[x].r)>>1

;

if(r<=mid) change(2*x,l,r,z);

else

if(l>mid) change(2*x+1

,l,r,z);

else

t[x].sum=(t[2*x].sum+t[2*x+1].sum)%mo;

}int query(int x,int l,int r)//

查詢區間和

if(t[x].lazy) update(x);

int mid=(t[x].l+t[x].r)>>1

;

if(r<=mid) return query(2*x,l,r);

else

if(l>mid) return query(2*x+1

,l,r);

else}//

上面是線段樹

void dfs1(int u,int

fa)}

void dfs2(int u,int

tp)

}void tchange(int x,int y,int

z)//

到一條鏈上之後跳出

if(dep[x]>dep[y]) swap(x,y);//

找到深度淺的那個

change(1,id[x],id[y],z);//

最後一條鏈加z

}int tcha(int x,int

y)

if(dep[x]>dep[y]) swap(x,y);

ans+=query(1

,id[x],id[y]);

ans%=mo;

return

ans;

}void changeson(int x,int

z)int chason(int

x)int

main()

for(int i=1;i)

dfs1(s,0);

dfs2(s,s);

build(

1,1,n);

for(int i=1;i<=m;i++)

else

if(op==2

)

else

if(op==3

)

else

if(op==4

)

}return0;

}

剛學會,理解還是不太到位,歡迎指正。

P3384 模板 樹鏈剖分

傳送門 題目描述 如題,已知一棵包含n個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作1 格式 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z 操作2 格式 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和 操作3 格式 3 x z 表示將以x為根...

P3384 模板 樹鏈剖分

p3384 模板 樹鏈剖分 樹鏈剖分是把一棵樹劃分成幾條鏈,這幾條鏈又能組成陣列,然後把陣列建成線段樹,繼而相當於在樹樹上操作。include include include include include using namespace std const int maxn 2e5 10 int ...

P3384 模板 樹鏈剖分

題目描述 如題,已知一棵包含n個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作1 格式 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z 操作2 格式 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和 操作3 格式 3 x z 表示將以x為根節點的子...