第一次接觸樹分治。打算今晚學的,先看了一蛤樹的重心怎麼求,之後知道了重心後再來看這道題,這種題是不是啟發式合併也可以?一遍一遍加邊地合併上去,然後列舉小的塊的每個點,二分大的塊,然而這還是要遍歷一遍小的塊再遍歷一遍大的塊才能預處理出道鏈結的兩個點的距離,就不滿足啟發式合併的nlogn了,因為要對大的塊進行遍歷,燃熱這個n<1e4,不是很大,說不定能水過去,然而t了。。。果然是樓教主的男人8題,極限資料很強。於是還是老老實實寫樹分治。
理解了一蛤以後,樹的點分治就是求出跟這個點有關的所有情況,然後把所有點的與該點有關的情況加在一起,得到最後的答案,在這道題中,就是列舉必須經過當前點的路徑有多少<=k的。由於枚舉子樹中所有dis[u]+dis[v]<=k的情況可以o(n)掃瞄得到,這個總數為,所以先加上這個總數,再減掉那些從同乙個子樹中到達根節點又回到同乙個子樹的路徑對剛才總數的貢獻,就得到了從乙個子樹經過該點到另外乙個子樹中對答案的所有貢獻。(還是有點沒想清楚,過一點時間再來看看)
網上**求樹的重心有問題,然而還是a了。然而網上**的樹的點分治寫法十分優秀,直接定義了乙個結構體centertree,然後再內部定區域性變數,方便每次找子樹後找到重心再變成一棵新樹。
2020.1.12 upd
終於懂那裡為什麼要減去每一棵相同子樹的貢獻了,因為長度相加得到<=j只能是經過當前u點且去往不同子樹的路徑,而無視所有路徑組合,相同子樹到root的距離加起來不是他們之間的距離,所以算完以後要減去每一棵子樹中自己的路徑組合。
#include#include#include#include#define maxl 10010
#define inf 2000000001
using namespace std;
int n,k,cnt,len,size,ans;
int dis[maxl],ehead[maxl],data[maxl];
struct ed
e[maxl<<1];
bool vis[maxl];
inline int max(int a,int b)
struct cntertree
res=max(res,n-son[u]);
if(res}
int getcenter(int x)
}tree;
inline void add(int u,int v,int l)
inline void prework()
}void getdata(int u,int fa)
}inline int calc(int u,int w)
return sum;
}void solve(int u)
}inline void mainwork()
inline void print()
int main()
return 0;
}
poj1741(樹的點分治)
題目連線 poj 1741 看了好長時間才明白了點.網上講解很多但感覺都不夠詳細。大概是太弱了吧 學通了再回來寫詳解。1 include2 include3 include4 include5 define ll long long 6using namespace std 7const int n...
POJ 1741 樹的分治
題意就是求樹上距離小於等於k的點對有多少個 n2的演算法肯定不行,因為1w個點 這就需要分治。可以看09年漆子超的 本題用到的是關於點的分治。乙個重要的問題是,為了防止退化,所以每次都要找到樹的重心然後分治下去,所謂重心,就是刪掉此結點後,剩下的結點最多的樹結點個數最小。每次分治,我們首先算出重心,...
POJ 1741 樹的分治
tree 求樹上兩點最短距離不超過 k 的對數。通過樹的分治的方法,從根節點自上而下開始求其不同子樹上的兩點通過該點的最短距離小於 k 的對數。有兩點需要注意 1.求某節點不同子樹滿足條件的兩點不好直接求。可以通過先求該節點的所有子節點滿足條件的個數,然後減去其子樹內所有滿足條件的點的個數。這個通過...