題目描述
有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個操作,分為三種:
操作 1 :把某個節點 x 的點權增加 a 。
操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。
操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。
輸入格式
第一行包含兩個整數 n, m 。表示點數和運算元。
接下來一行 n 個整數,表示樹中節點的初始權值。
接下來 n-1 行每行兩個正整數 from, to , 表示該樹中存在一條邊 (from, to) 。
再接下來 m 行,每行分別表示一次操作。其中第乙個數表示該操作的種類( 1-3 ) ,之後接這個操作的引數( x 或者 x a ) 。
輸出格式
對於每個詢問操作,輸出該詢問的答案。答案之間用換行隔開。
輸入輸出樣例
輸入 #1 複製
5 51 2 3 4 5
1 21 4
2 32 5
3 31 2 1
3 52 1 2
3 3輸出 #1 複製69
13說明/提示
對於 100% 的資料, n,m<=100000 ,且所有輸入資料的絕對值都不會超過 10^6 。
很明顯的樹鏈剖分,也可以考慮 lct 直接維護就好了,維護區間和,然後對線段樹區間更新,怎麼修改子樹所有權值呢?因為樹鏈剖分具有dfs序一樣的性質,子樹連續,所以我們只要知道子樹的大小即可,然後子樹的大小在樹鏈剖分dfs1的時候已經維護了,所以更新即可。
為什麼要寫這麼裸的部落格呢?(經常更新部落格,證明我還活著!!!)
ac**:
#pragma gcc optimize(2)
#include
#define int long long
using namespace std;
const
int n=
1e5+10;
int n,m,val[n]
,h[n]
,pos[n]
,bl[n]
,f[n]
,sz[n]
,cnt;
int head[n]
,nex[n<<1]
,to[n<<1]
,tot;
inline
void
add(
int a,
int b)
struct nodet[n<<2]
;void
dfs1
(int x)
}void
dfs2
(int x,
int belong)
inline
void
push_up
(int p)
inline
void
push_down
(int p)
}void
build
(int p,
int l,
int r)
void
change
(int p,
int l,
int r,
int v)
push_down
(p);
int mid=t[p]
.l+t[p]
.r>>1;
if(r<=mid)
change
(p<<
1,l,r,v)
;else
if(l>mid)
change
(p<<1|
1,l,r,v)
;else
change
(p<<
1,l,mid,v)
,change
(p<<1|
1,mid+
1,r,v)
;push_up
(p);
}int
ask(
int p,
int l,
int r)
intquery
(int x,
int y)
if(pos[x]
>pos[y]
)swap
(x,y)
; res+
=ask(1
,pos[x]
,pos[y]);
return res;
}signed
main()
dfs1(1
);dfs2(1
,1);
build(1
,1,n);
for(
int i=
1;i<=n;i++
)change(1
,pos[i]
,pos[i]
,val[i]);
while
(m--
)return0;
}
HAOI2015 樹上操作
有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。輸入格式 第一行包含兩個整數 n,m 表示點數和運算元。...
HAOI2015 樹上操作
嘟嘟嘟 樹剖自然可解,就是一道板子題,而且這道題還只問到根節點的距離是多少,而不是樹上任意兩點距離,就更方便了。1 include2 include3 include4 include5 include6 include7 include8 include9 include10 include11 ...
HAOI2015 樹上操作
題目 bzoj4034 洛谷p3178。題目大意 有一棵點數為 n 的樹,以點 1 為根,且樹有點權。然後有 m 個操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。現在要你...