設 \(f[u]\) 為以1為根時,u節點的子樹中的答案。
設 \(g[u]\) 為以1為根時,u節點向父親p方向看,包括父親p但不包括u節點的子樹中的答案。
則答案為 \(f[u]+g[u]\)
當維護g的運算是乙個群時,可以直接用逆運算去掉當前節點u的貢獻。
void dfs1(int u, int p)
}void dfs2(int u, int p)
for(int &v : g[u])
}
當維護的運算是不存在逆元的半群時,要用奇奇怪怪的方法計算。例如假如是要求最大值,那麼就維護第1大和第2大。
struct max2
// insert value v
void insert(int v)
}// remove value v and query max
int removemax(int v)
};
題意:給一棵樹,對於每個點,問是否可以在(你自己想要怎麼操作就怎麼操作)一次操作之後使得刪去這個點之後剩下的連通塊的大小都不超過n/2。操作為刪除一條邊然後加上一條邊,並保證操作之後仍然是一棵樹。
題解:設siz[u]為以1為根時,子樹的siz。設 x[u] 為 以 u 為根時,最大的子樹的siz,設y1[u] 為以 1為根時,u節點內的不超過n/2的最大的子樹的siz,設 y2[u] 為從以 1 為根換到以u為根時,從u節點方向往下看,看到p節點內的不超過n/2的最大的子樹的siz。答案為x[u]<=n/2,或者以u為根時,那棵唯一的最大的子樹減去其不超過n/2的最大的子樹(並把這個子樹直接連線到u上面)之後的siz不超過n/2。
麻煩的是y2[u],y2[u]=n-siz[u]\leq n/2 ? n-siz[u] : max(y2[p],\max_y1[v]) ,後面這個遍歷p節點的子樹的所有y1[v],然後除去y1[u]之後的最大值,需要用上面的max2資料結構來維護。
樹形 dp 換根 dp
樹形dp 樹形動歸一般是依賴於dfs的,根據動歸的後效性,父節點的狀態一般都依賴子節點的狀態以某種方式轉移而來 換根的p2015 設f i j 表示i的子樹上保留j條邊最多蘋果數 p2279 狀態表示f x 0 覆蓋到x的爺爺和x整棵子樹 向上2層 最少個數 f x 1 覆蓋到x的父親和x子樹 向上...
樹形DP 換根DP
某些樹形dp問題中,我們要求的值是類似 以當前節點為根節點得到的答案 卻沒有給出固定的根節點,若仍然按照常規的樹形dp思路對每個點進行dp,我們對每乙個節點均進行一次 dfs 最後的複雜度是 o left n 2 right 如果我們先假設任意乙個點為根進行 dp,求出當前樹形結構下以每個點為根的子...
換根dp入門
本題是要你任選乙個點為根使得樹上的所有點深度之和最小。本題是要你任選乙個點為根使得樹上的所有點深度之和最小。首先考慮如果是指定根節點你會不會做 已知根節點的話,我們只需要一遍dfs 或者bfs 就可以求出每個點的深度,然後求和就可以了。然後我們考慮如果我們知道當前節點x為根的結果能否快速求出以它某兒...