在一片土地上有 \(n\) 個城市,通過 \(n-1\) 條無向邊互相連線,形成一棵樹的結構,相鄰兩個城市的距離為 \(1\),其中第 \(i\) 個城市的價值為 \(value_i\)。
不幸的是,這片土地常常發生**,並且隨著時代的發展,城市的價值也往往會發生變動。
0 x k
表示發生了一次**,震中城市為 \(x\),影響範圍為 \(k\),所有與 \(x\) 距離不超過 \(k\) 的城市都將受到影響,該次**造成的經濟損失為所有受影響城市的價值和。
1 x y
表示第 \(x\) 個城市的價值變成了 \(y\) 。
點分樹就是在點分治的基礎上,將每次跳的重心與上一次跳的重心連邊,構成一棵點分樹。也就是乙個點 \(x\) 的子節點是點分治時以 \(x\) 為重心的子樹扔掉點 \(x\) 後,其餘所有的樹的重心。
由於點分治只會遞迴 \(\log n\) 層,所以點分樹的深度也是 \(o(\log n)\) 的。
對於本題,構建出點分樹,對於每乙個點 \(x\),我們維護兩棵動態開點線段樹,第一棵的乙個區間 \([l,r]\) 表示在點分樹以 \(x\) 為根的子樹中,原樹上與 \(x\) 距離在 \([l,r]\) 的點的權值和;第二棵線段樹區間 \([l,r]\) 表示在點分樹以 \(x\) 為根的子樹中,原樹上與 \(x\) 在點分樹上的父親之間的距離在 \([l,r]\) 的點的權值和。
對於修改操作,我們從點 \(x\) 不斷往點分樹上父親跳,然後維護兩棵線段樹的值即可。
對於詢問操作,我們依然從點 \(x\) 開始網上跳,對於跳到的乙個節點 \(a\),設上乙個調到的節點 \(b\),那麼 \(a\) 會造成的貢獻為距離 \(a\) 不超過 \(k-dis_\) 的點。但是在 \(b\) 中已經有一部分點背計算過了,這樣就會導致重複計算,所以還要減去 \(b\) 的第二棵線段樹中不超過 \(k-dis_\) 的點。
這樣就可以在 \(o(n\log^2n)\) 的複雜度內計算出答案了。
由於這種做法常數較大,我們可以用 st 表預處理 lca,每次詢問可以 \(o(1)\) 查,並且動態開點線段樹可以改為離散化後的樹狀陣列。注意每乙個樹狀陣列的大小應當分別離散化,且離散化後大小應為其點分樹內子樹大小。這樣空間複雜度是 \(o(n\log n)\) 的。
#include using namespace std;
const int n=200010,lg=18,inf=1e9;
int head[n],size[n],dfn[n],maxp[n],fa[n],dep[n],val[n],lg[n],st[n][lg+1];
int n,m,tot,rt,last;
bool vis[n];
vectordis[2][n];
struct edge
e[n*2];
void add(int from,int to)
; head[from]=tot;
}void dfs1(int x,int f) }}
void getst()
} if (sum-size[x]>maxp[x]) maxp[x]=sum-size[x];
if (maxp[x]c;
void add(int x,int v) }
return ans;
}int main()
for (int i=1;i<=n;i++)
for (int i=1;i<=n;i++)
while (m--)
return 0;
}
P6329 模板 點分樹 震波
題目連線 關於點分樹的一些地方今天終於弄明白了,這個題理解的還可以,就是有點卡常,調了好久還是跑的很慢。include include include include include include include include include include define ll long lon...
Luogu6329 模板 點分樹 震波
終於寫了點分樹,iee 資料範圍 n,m le 10 5 權值範圍是 1,10 4 洛谷時限 2s。首先點分治可以用來解決路徑問題,因為 u,v 在點分樹上的 lca 一定在原樹路徑上,同時保證了深度 log n 如果不帶修的話,首先每個點維護乙個 vector,下標為該點在點分樹上的子樹到該點的距...
洛谷 P3384 模板 樹鏈剖分
如題,已知一棵包含n個結點的樹 連通且無環 每個節點上包含乙個數值,需要支援以下操作 操作1 格式 1 x y z 表示將樹從x到y結點最短路徑上所有節點的值都加上z 操作2 格式 2 x y 表示求樹從x到y結點最短路徑上所有節點的值之和 操作3 格式 3 x z 表示將以x為根節點的子樹內所有節...