點分治:
優雅地暴力解決一類不帶修改的樹上路徑問題。
每次找原樹的重心,以重心為根暴力列舉當前子樹內的所有點算答案,然後繼續遞迴子樹。
這個東西最多會遞迴$\log$層,所以複雜度是$o(n\log)$的。
#include#include點分治動態點分治(點分樹):#include
#include
#define maxn 100005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long
using
namespace
std;
int n,m,k,hd[maxn],to[maxn<<1],nxt[maxn<<1],cst[maxn<<1
];int
rt,ans,num,siz[maxn],d[maxn],q[maxn],tot,mnsiz,cnt;
bool
vis[maxn];
inline
intread()
inline
void addedge(int u,int v,int
w)inline
void getrt(int u,int
fa) mx=max(mx,tot-siz[u]);
if(mxmx;
return;}
inline
void getdis(int u,int
fa)
return;}
inline
int calc(int u,int
val)
return
res;
}inline
void dfs(int
u)
return;}
intmain()
while(m--)
return0;
}
解決帶修改的點分治問題。
按dfs的順序把點分治的所有重心連成一棵樹,每次修改在樹上跳fa更新貢獻。
注意這棵樹破壞了原樹的結構,所以需要容斥的地方可能要單獨維護。
複雜度$o(n\log)$。(luogu這麼喜歡模板題卡常啊?)
#include#include動態點分治#include
#include
#define maxn 100005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long
using
namespace
std;
int n,m,k,hd[maxn],to[maxn<<1],nxt[maxn<<1],cst[maxn<<1
];int
rt,ans,num,siz[maxn],d[maxn],q[maxn],tot,mnsiz,cnt;
bool
vis[maxn];
inline
intread()
inline
void addedge(int u,int v,int
w)inline
void getrt(int u,int
fa) mx=max(mx,tot-siz[u]);
if(mxmx;
return;}
inline
void getdis(int u,int
fa)
return;}
inline
int calc(int u,int
val)
return
res;
}inline
void dfs(int
u)
return;}
intmain()
while(m--)
return0;
}
點分治 動態點分治
實在拖得太久了。先扔掉資料 分治的核心是盡量把乙個整體分成接近的兩個部分,這樣遞迴處理可以讓複雜度從n 變成nlogn。兩個問題,如何區分和如何算答案。對於第乙個問題,重心,然後就是找重心的方法,兩個dfs,對於第二個問題,對於每個重心算當前塊中每個點到重心的答案,然後由重心分開的塊要把多餘的資訊去...
點分治與動態點分治
點分治一般是用於解決樹上路徑問題。樹的重心 把重心這個點割掉後,使所形成的最大的聯通塊大小最小的點。可以證明重心子樹的大小最大不會超過 n over 2 重心可以通過 dfs 一遍求出。maxsiz x 表示割掉點x後所形成的的最大的聯通塊的大小 void dfs int x,int fa max ...
動態點分治
由於蒟蒻太遜,現在才開始學動態點分治,寫乙個 blog 吧。動態點分治是利用點分治的過程,建成一顆由子樹重心連線而成的點分樹,這棵樹的高度為 log n 級別的,因此可以通過暴力跳父親完成修改操作。建立點分樹的過程,就是按照點分治的流程,記錄上級重心並連線,即可獲得一棵點分樹。點分樹的結構與原樹不相...