有一棵點數為 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 369
13題解
又是一道裸的樹鏈剖分。
這裡有乙個新的操作,子樹加。我們發現子樹是一段連續的區間,所以在dfs2是標記一下右端點就行了。
#include#include#include#include#define ll long long
using namespace std;
const int maxn=200010;
int pre[maxn],last[maxn],other[maxn],num,dfs[maxn],top[maxn],dep[maxn];
int r[maxn],sz[maxn],fa[maxn],son[maxn],n,m,belong[maxn];
int cnt;
ll w[maxn];
struct treet[maxn*4];
void add(int x,int y)
void dfs1(int x)
void update(int x)
t[x*2].sum+=(ll)(t[x*2].r-t[x*2].l+1)*t[x].lazy;
t[x*2].lazy+=t[x].lazy;
t[x*2+1].sum+=(ll)(t[x*2+1].r-t[x*2+1].l+1)*t[x].lazy;
t[x*2+1].lazy+=t[x].lazy;
t[x].lazy=0;
}void change(int x,int l,int r,long long k)
if(t[x].lazy)
update(x);
change(x*2,l,r,k);
change(x*2+1,l,r,k);
t[x].sum=t[x*2].sum+t[x*2+1].sum;
}ll query(int x,int l,int r)
if(t[x].lazy)
update(x);
return query(x*2,l,r)+query(x*2+1,l,r);
}ll work(int l,int r)
int main(){
int x,type;long long y;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&w[i]);
for(int i=1;i
bzoj4034 HAOI2015 樹上操作
傳送門 description 有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個 操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。input 第一行包含...
bzoj 4034 HAOI2015 樹上操作
4034 haoi2015 樹上操作 time limit 10 sec memory limit 256 mb submit 4216 solved 1340 submit status discuss description 有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個 ...
BZOJ 4034 HAOI2015 樹上操作
有一棵點數為 n 的樹,以點 1 為根,且樹點有邊權。然後有 m 個 操作,分為三種 操作 1 把某個節點 x 的點權增加 a 操作 2 把某個節點 x 為根的子樹中所有點的點權都增加 a 操作 3 詢問某個節點 x 到根的路徑中所有點的點權和。第一行包含兩個整數 n,m 表示點數和運算元。接下來一...