bzoj4034 樹上操作

2021-08-29 05:12:22 字數 1951 閱讀 9127

有一棵點數為 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 51 2 3 4 5

1 21 4

2 32 5

3 31 2 1

3 52 1 2

3 36913

用樹狀陣列+dfs序

我們先用乙個樹狀陣列維護每乙個點(的dfs序)到根節點的值,對於第乙個操作,如果把x這個點+k,相當於把以x為根的子樹的所有點都加上k,因為這棵子樹的dfs序是連續的,所以可以用樹狀陣列維護。而對於第二個操作,講x的個點和其子樹都+k,我們可以先假設,如果只往根節點+k,那麼查詢每乙個點時,就相當於加上了其深度depth*k。如果要往其他點+k,我們可以令開乙個樹狀陣列,維護以x為根節點的子樹的+k,然後,答案就是第乙個樹狀陣列+(depth當前點-depthx)*第二課樹狀陣列。但是,我們在查詢時並不知道depthx是什麼,因此,在第二個操作時,讓第一顆樹狀陣列減去(depthx-1)*k。

#include #include 

#include

#include

#include

#include

#define rep(i,k,n) for(long long i=k;i<=n;i++)

#define in(a) a=read()

#define maxn 100010

using

namespace

std;

inline

long

long

read()

queue

long>q;

long

long

n,m;

long

long total=0,head[maxn],nxt[maxn<<1],to[maxn<<1

];long

long

l[maxn],r[maxn],depth[maxn],dfn[maxn],cnt;

long

long tree[2][maxn<<2

];long

long

arr[maxn];

long

long lowbit(long

long

k)inline

void adl(long

long a,long

long

b)void dfs(long

long u,long

long

fa) r[u]=cnt;

}inline

void add(long

long f,long

long s,long

long

k)inline

long

long query(long

long f,long

long

s)int

main()

return0;

}/*5 51 2

1 42 3

2 5*/

bzoj4034 樹上操作

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

題解 bzoj4034 樹上操作

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

bzoj4034 HAOI2015 樹上操作

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