題解 bzoj4034 樹上操作

2021-08-03 18:09:09 字數 1496 閱讀 9170

有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個

操作,分為三種:

操作 1 :把某個節點 x 的點權增加 a 。

操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。

操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。

第一行包含兩個整數 n, m 。表示點數和運算元。接下來一行 n 個整數,表示樹中節點的初始權值。接下來 n-1

行每行三個正整數 fr, to , 表示該樹中存在一條邊 (fr, to) 。再接下來 m 行,每行分別表示一次操作。其中

第乙個數表示該操作的種類( 1-3 ) ,之後接這個操作的引數( x 或者 x a ) 。

對於每個詢問操作,輸出該詢問的答案。答案之間用換行隔開。

5 5

1 2 3 4 5

1 2

1 4

2 3

2 5

3 3

1 2 1

3 5

2 1 2

3 36

9 13

對於 100% 的資料, n,m<=100000 ,且所有輸入資料的絕對值都不會超過 10^6 。

這題本來是樹鏈剖分裸題。但是這題可以用線段樹的o(

nlog

2n) 演算法完成n=

106的做法。線段樹直接在dfs序上維護每個點到根的距離即可,相當於線段樹上區間修改、區間按每個點的權值(深度)相關修改、單點查詢。

**:

#include

#include

using namespace std;

templateinline void read(t &x)

typedef long long ll;

const int maxn=100010;

int n,m,num,head[maxn],dfn[maxn],cnt,tl[maxn],tr[maxn],dep[maxn];

ll a[maxn],w[maxn];

struct edgee[maxn<<1];

struct segment_tree

void pushdown(int

x) if(tag[x])

}void add1(int

x,int l,int r,ll val)

void add2(int

x,int l,int r,ll val)

ll query(int

x,int

pos)

}tree;

void add(int u,int v)

void dfs(int

x,int fa)

int main()

else

if(opt==2)

else

printf("%lld\n",tree.query(1,tl[x]));

}return

0;}

bzoj4034 樹上操作

有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個 操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。第一行包含兩個整數 n,m 表示點數和運算元。接下來一...

bzoj4034 樹上操作

dfs序 注意出棧時也要加入 然後對於每一次乙個節點的修改,都在左端點上打 x,右端點上打 x,區間修改同理 因此要用線段樹且需要維護區間左端點數量 右端點數量 對於詢問操作,就是 dfs序上的一段字首和,用線段樹處理即可。1 include2 include3 define ll long lon...

bzoj4034 HAOI2015 樹上操作

傳送門 description 有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個 操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。input 第一行包含...