這題其實就是樹剖裸題啊。
然後毒瘤選手由於上題樹剖被卡到哭所以選擇dfs序+樹狀陣列。
不得不說簡單的演算法做出來更加難思考。然後網上的dalao們都一筆帶過淨說什麼用兩個樹狀陣列維護就可以啦。
經過大半小時的思考,**實現還是非常簡單。
這個值得詳細講講。
假如我們弄乙個樹狀陣列,然後維護的是x到根的sum(其實就是詢問的答案嘛),先看第乙個操作,單點修改,那麼改了這個點,相當於把他這一整棵子樹的答案都加上了d,由於用dfs序重新編號,可以發現子樹中的點都是連續的,那麼樹狀陣列改段求段就可以用差分陣列解決。
問題在於第二個操作,修改了整個子樹,對每個節點y的影響是d*(dep[x]-dep[y]),那麼非常難受,因為每個點改變的值和dep有關,並不相同,怎麼辦?絕佳的方法就是我們忽略dep的影響,用另乙個樹狀陣列維護d,那麼問題又來了,x肯定不是時時相同的,雖然詢問y的時候可以知道dep[y],但是dep[x]仍然不確定,為了可以確定,那麼對於每次這種修改,我們就在第乙個樹狀陣列給它減去d*(dep[x]-1),這樣一來,就把這個操作轉化成增加x整個子樹和x到根的路徑上的點,那麼對於每個點,增加的數就變成d*dep[y],那麼求解的時候,就可以心安理得的用第乙個樹狀陣列的值+第二個樹狀陣列的值*d了。
#include#include#include
#include
#include
#include
using
namespace
std;
typedef
long
long
ll;int
n,m;
struct
node
a[210000];int len,last[110000
];void ins(int x,int
y)int z,dep[110000],l[110000],r[110000
];void dfs(int x,int
f) r[x]=z;}//
---------init-----------------
ll s[
2][110000
];int lowbit(int x)
void change(int w,int
x,ll k)
}ll getsum(
int w,int
x)
return
ret;}//
-----------bit--------------
ll point[
110000
];int
main()
z=0;dep[1]=1;dfs(1,0
);
//init
for(int i=1;i<=n;i++)
change(
0,l[i],point[i]), change(0,r[i]+1,-point[i]);
intop;ll d;
for(int i=1;i<=m;i++)
else
if(op==2
)
else
}return0;
}
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 表示點數和運算元。接下來一...