两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
technique:centroid_decomposition [2020/06/05 23:25] jxm2001 汇报 |
technique:centroid_decomposition [2020/06/11 21:45] (当前版本) admin finish |
||
---|---|---|---|
行 1: | 行 1: | ||
- | **格式**:大部分已修改 | ||
- | - 注意句号 | ||
- | - ''\left(\right)'' 通常用于括号内部内容较多的情况 | ||
- | - sum 建议用 ''\text'' 包裹 | ||
- | |||
- | **内容**: | ||
- | - 例 4 中至少要大致描述一下单调队列维护的东西,不能太简略(已完成) | ||
- | - 例 5 中不能只给代码,无论如何都要讲一下大致做法。(已完成) | ||
- | - 方便的话完善一下例 4、5 中更好的解法。(我只知道有,但我不会) | ||
- | |||
====== 静态点分治 ====== | ====== 静态点分治 ====== | ||
行 23: | 行 13: | ||
如果选取树的重心作为根结点,则每棵子树的结点个数不超过 $\frac n2$ ,可以保证递归深度不超过 $\log n$。 | 如果选取树的重心作为根结点,则每棵子树的结点个数不超过 $\frac n2$ ,可以保证递归深度不超过 $\log n$。 | ||
- | 在这个基础上如果能在 $O(n)$ 时间维护经过根结点路径相关信息,则算法总时间复杂度为 $O(n\log n)$。 | + | 在这个基础上如果能在 $O(n\log^{\alpha}n)$ 的时间内维护经过根结点路径相关信息,则算法总时间复杂度为 $O(n\log^{\alpha+1}n)$,即复杂度只增加一个 $\log$。 |
===== 代码实现 ===== | ===== 代码实现 ===== | ||
- | 重心的寻找可使用 dfs,处理出所有结点的 $\text{sz}$ ,所有结点的最大子树 $\text{mson}(u)=\max\left(\max\left(\text{sz}\left(\text{son}\left(u\right)\right),\text{tot_sz}-\text{sz}\left(u\right)\right)\right)$。 | + | 重心的寻找可使用 ''dfs'',处理出所有结点的 $\text{sz}$ ,所有结点的最大子树 $\text{mson}(u)=\max\left(\max\left(\text{sz}\left(\text{son}\left(u\right)\right),\text{tot_sz}-\text{sz}\left(u\right)\right)\right)$。 |
不断更新 $\text{mson}$ 最小的结点,最后便可以得到重心,时间复杂度 $O(n)$。 | 不断更新 $\text{mson}$ 最小的结点,最后便可以得到重心,时间复杂度 $O(n)$。 | ||
行 56: | 行 46: | ||
} | } | ||
void solve(int u){ | void solve(int u){ | ||
+ | int cur_sz=tot_sz; | ||
vis[u]=true;query(u); | vis[u]=true;query(u); | ||
for(int i=head[u];i;i=edge[i].next){ | for(int i=head[u];i;i=edge[i].next){ | ||
行 61: | 行 52: | ||
if(vis[v]) | if(vis[v]) | ||
continue; | continue; | ||
- | tot_sz=sz[v];root_sz=inf; | + | tot_sz=sz[v]>sz[u]?cur_sz-sz[u]:sz[v];root_sz=inf; |
find_root(v,u); | find_root(v,u); | ||
solve(root); | solve(root); | ||
行 149: | 行 140: | ||
void query(int u){ | void query(int u){ | ||
sd.clear(); | sd.clear(); | ||
+ | mark[0]=true; | ||
for(int i=head[u];i;i=edge[i].next){ | for(int i=head[u];i;i=edge[i].next){ | ||
d.clear(); | d.clear(); | ||
行 172: | 行 164: | ||
} | } | ||
void solve(int u){ | void solve(int u){ | ||
- | vis[u]=mark[0]=true;query(u); | + | int cur_sz=tot_sz; |
+ | vis[u]=true;query(u); | ||
for(int i=head[u];i;i=edge[i].next){ | for(int i=head[u];i;i=edge[i].next){ | ||
int v=edge[i].to; | int v=edge[i].to; | ||
if(vis[v]) | if(vis[v]) | ||
continue; | continue; | ||
- | tot_sz=sz[v];root_sz=inf; | + | tot_sz=sz[v]>sz[u]?cur_sz-sz[u]:sz[v];root_sz=inf; |
find_root(v,u); | find_root(v,u); | ||
solve(root); | solve(root); | ||
行 295: | 行 288: | ||
} | } | ||
void solve(int u){ | void solve(int u){ | ||
+ | int cur_sz=tot_sz; | ||
vis[u]=true;query(u); | vis[u]=true;query(u); | ||
for(int i=head[u];i;i=edge[i].next){ | for(int i=head[u];i;i=edge[i].next){ | ||
行 300: | 行 294: | ||
if(vis[v]) | if(vis[v]) | ||
continue; | continue; | ||
- | tot_sz=sz[v];root_sz=MAXN; | + | tot_sz=sz[v]>sz[u]?cur_sz-sz[u]:sz[v];root_sz=MAXN; |
find_root(v,u); | find_root(v,u); | ||
solve(root); | solve(root); | ||
行 505: | 行 499: | ||
} | } | ||
void solve(int u){ | void solve(int u){ | ||
+ | int cur_sz=tot_sz; | ||
vis[u]=true;query(u); | vis[u]=true;query(u); | ||
for(int i=head[u];i;i=edge[i].next){ | for(int i=head[u];i;i=edge[i].next){ | ||
行 510: | 行 505: | ||
if(vis[v]) | if(vis[v]) | ||
continue; | continue; | ||
- | tot_sz=sz[v];root_sz=MAXN; | + | tot_sz=sz[v]>sz[u]?cur_sz-sz[u]:sz[v];root_sz=MAXN; |
find_root(v,u); | find_root(v,u); | ||
solve(root); | solve(root); |