P3384 模板 輕重鏈剖分(樹鏈剖分模板)

2021-10-22 09:30:58 字數 3820 閱讀 3373

入口

題目描述

如題,已知一棵包含 nn 個結點的樹(連通且無環),每個節點上包含乙個數值,需要支援以下操作:

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

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

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

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

輸入格式

第一行包含 44 個正整數 n,m,r,pn,m,r,p,分別表示樹的結點個數、操作個數、根節點序號和取模數(即所有的輸出結果均對此取模)。

接下來一行包含 nn 個非負整數,分別依次表示各個節點上初始的數值。

接下來 n-1n−1 行每行包含兩個整數 x,yx,y,表示點 xx 和點 yy 之間連有一條邊(保證無環且連通)。

接下來 mm 行每行包含若干個正整數,每行表示乙個操作,格式如下:

操作 11: 1\ x\ y\ z1 x y z;

操作 22: 2\ x\ y2 x y;

操作 33: 3\ x\ z3 x z;

操作 44: 4\ x4 x。

輸出格式

輸出包含若干行,分別依次表示每個操作 22 或操作 44 所得的結果(對 pp 取模)。

輸入輸出樣例

輸入 #1複製

5 5 2 24

7 3 7 8 0

1 21 5

3 14 1

3 4 2

3 2 2

4 51 5 1 3

2 1 3

輸出 #1複製221

說明/提示

資料規模:

對於 30%30% 的資料: 1 \leq n \leq 10,1 \leq m \leq 101≤n≤10,1≤m≤10;

對於 70%70% 的資料: 1 \leq n \leq ^3, 1 \leq m \leq ^31≤n≤10

3,1≤m≤103;

對於 100%100% 的資料: 1\le n \leq ^5, 1\le m \leq ^5,1\le r\le n,1\le p \le 2^-11≤n≤10

5,1≤m≤10

5,1≤r≤n,1≤p≤2

31−1。

當做模板用就行,不解釋了

#

include

#define

inf0x7fffffff

#define

lllong

long

#define

intlong

long

//#define double long double

#define

eps1e-8

//#define mod 1e9+7

using

namespace std;

//const int mod=1e9+7;

const

int m=

1e7+5;

const

int n=

1e6+5;

//?????????? 4e8

struct

node

e[n]

;struct

tree

t[n]

;int dep[n]

,dfn[n]

,son[n]

,sz[n]

,fa[n]

;int n,m,root,mod;

int tot=

1,head[n]

;int a[n]

,num,top[n]

,w[n]

;void

add(

int x,

int y)

void

addedge

(int x,

int y)

void

dfs1

(int x,

int pre)}}

void

dfs2

(int x,

int pre)

}void

bulid

(int q,

int l,

int r)

int mid=

(l+r)

>>1;

bulid

(q<<

1,l,mid)

;bulid

(q<<1|

1,mid+

1,r)

; t[q]

.val=

(t[q<<1]

.val+t[q<<1|

1].val)

%mod;

}void

spread

(int q)

}void

change

(int q,

int l,

int r,

int v)

spread

(q);

int mid=

(t[q]

.l+t[q]

.r)>>1;

if(l<=mid)

change

(q<<

1,l,r,v);if

(midchange

(q<<1|

1,l,r,v)

; t[q]

.val=

(t[q<<1]

.val+t[q<<1|

1].val)

%mod;

}int

ask(

int q,

int l,

int r)

void

mson

(int x,

int v)

//以x為根的子樹的所有節點+v

intqson

(int x)

//以x為根的子樹的所有節點+v 的和

void

mchain

(int x,

int y,

int z)

//修改鏈 (x->y)

if(dep[x]

>dep[y]

)swap

(x,y)

;change(1

,dfn[x]

,dfn[y]

,z);

}int

qchain

(int x,

int y)

//查詢鏈 (x->y)

if(dep[x]

>dep[y]

)swap

(x,y)

; ans=

(ans+

ask(

1,dfn[x]

,dfn[y]))

%mod;

return ans%mod;

}void

solve()

dfs1

(root,root)

;dfs2

(root,root)

;bulid(1

,1,n);

while

(m--

)else

if(f==2)

else

if(f==3)

else

printf

("%lld\n"

,qson

(x));}

}signed

main()

P3384 輕重鏈剖分(樹剖模板)

如題,已知一棵包含 nn 個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作 11 格式 1 x y z1xyz 表示將樹從 xx 到 yy 結點最短路徑上所有節點的值都加上 zz。操作 22 格式 2 x y2xy 表示求樹從 xx 到 yy 結點最短路徑上所有節點的值之和。操...

洛谷 P3384 模板 輕重鏈剖分(樹鏈剖分)

簡單點說,就是把一棵樹變成多條鏈。這裡說的是重鏈剖分。在遍歷一顆樹的時候,我們強制從父親節點走向兒子時,先走所有兒子中以兒子為根的子樹最大的那個兒子。其他的兒子不管什麼順序都可。這樣就可以把dfs序作為鏈。例如上面這棵樹,邊上的藍色數字就是遍歷順序。說一些定義 重邊 父親結點和重兒子連成的邊 輕邊 ...

樹鏈剖分 P3384 模板 樹鏈剖分

題目描述 戳這裡 題解 其實樹剖的重點就在於輕重鏈,這篇文章寫的很好 然而我線段樹寫得全是問題,改了半天2333 如下 include include include using namespace std const int maxn 100005 int n,m,root,tt,tot,lnk ...