BZOJ3384 模板題 樹鏈剖分

2021-08-19 08:40:37 字數 2984 閱讀 7549

題目鏈結

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

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

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

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

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

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

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

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

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

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

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

5 5 2 24

7 3 7 8 0

1 2

1 5

3 1

4 1

3 4 2

3 2 2

4 5

1 5 1 3

2 1 3

2 21

對於100%的資料: n≤105,m≤105 n \leq ^5, m \leq ^5 n≤105,m≤105

樹鏈剖分+線段樹區間更新查詢區間和

#include

#include

#include

#include

#include

using

namespace

std;

typedef

long

long ll;

const

int maxn = 100000 + 5;

ll p;//mod

int aa[maxn];

int siz[maxn];//子樹大小包括自己

int dep[maxn];//深度

int top[maxn];//重鏈起點

int fa[maxn];//父親

int son[maxn];//重鏈上的兒子

int num[maxn];//線段樹標號

int pre[maxn];//num的反函式

int vis[maxn];//標記走過

vector

v[maxn];//邊

ll tre[maxn << 2];//線段樹所在點的區間和

ll add[maxn << 2];//線段樹laz

int n;//總節點數

ll ans;//樹上查詢的答案

int tot;//dfs序所需

void update(int t, int l, int r, int x, int y, ll k);//線段樹更新

void query(int t, int l, int r, int x, int y, ll ad);//線段樹查詢

int dfs1(int last, int t);//第一次dfs

void dfs(int t, int ttop);//第二次dfs

void update_on_tree(int a, int b, ll z);//樹上路徑更新,a-b都加z

void query_on_tree(int a, int b);//樹上路徑查詢a-b

int dfs1(int last, int t)}}

if (i >= 0)

son[t] = v[t][i];

else

son[t] = -1;

return siz[t];

}void dfs(int t, int ttop)

}}void update(int t, int l, int r, int x, int y, ll k)

int mid = l + r >> 1;

if (y <= mid)

else

if (x > mid)

else

}void query(int t, int l, int r, int x, int y, ll ad)

int mid = l + r >> 1;

if (y <= mid)

else

if (x > mid)

else

}void update_on_tree(int a, int b, ll z)

update(1, 1, n, num[top[a]], num[a], z);

update_on_tree(fa[top[a]], b, z);

}void query_on_tree(int a, int b)

query(1, 1, n, num[top[a]], num[a], 0);

query_on_tree(fa[top[a]], b);

return;

}void build(int t, int l, int r)

int mid = l + r >> 1;

build(t << 1, l, mid);

build(t << 1 | 1, mid + 1, r);

tre[t] = tre[t << 1] + tre[t << 1 | 1];

}int main()

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

dep[r] = 1;

tot = 1;

dfs1(r, r);

memset(vis, 0, sizeof(vis));

dfs(r, r);

build(1, 1, n);

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

}}

p3384 樹鏈剖分模板題

樹鏈剖分的 實在是長,少有的幾次 行數過百了 線段樹 在圖論裡面的應用 線段樹是處理區間問題的 在圖論的樹裡面的應用就是通過重鏈的方式dfs編號,形成一段連續的區間,就可以用線段樹來處理了 能做到的事情為 如題,已知一棵包含n個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作1 ...

樹鏈剖分 P3384 模板 樹鏈剖分

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

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

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