【前言】
最近一段时间变成了通过题目学习算法,似乎整个人都乱套了(反思ing)
不过还好,现在又调整为了学算法后做题。(唉,最近一段时间有点急躁,要记住万事不能速成啊)
【正题】点分治
一句话:点分治主要用于树上路径点权统计问题。
一、【具体流程】
1,选取一个点,将无根树变成有根树
为了使每次的处理最优,我们通常要选取树的重心。
何为“重心”,就是要保证与此点连接的子树的节点数最大值最小,可以防止被卡。
重心求法:
1。dfs一次,算出以每个点为根的子树大小。
2。记录以每个节点为根的最大子树大小
3。判断:如果以当前节点为根更优,就更新当前根。
void getroot(int v,int fa)
{
son[v] = 1; f[v] = 0;//f记录以v为根的最大子树的大小
for(int i = head[v];i;i=e[i].next)
if(e[i].to != fa && !vis[e[i].to]) {
getroot(e[i].to,v);//递归更新
son[v] += son[e[i].to];
f[v] = max(f[v],son[e[i].to]);//比较每个子树
}
f[v] = max(f[v],sum-son[v]);//别忘了以v父节点为根的子树
if(f[v] < f[root]) root = v;//更新当前根
}
2、处理连通块中通过根节点的路径。
(注意,是通过根节点的路径,所以后面要去掉同一子树内部的路径,即去重)
3、标记根节点(相当于处理后,将根节点从子树中删除)。
4、递归处理当前点为根的每棵子树。
int solve(int v)
{
vis[v] = 1;//标记
for(int i = head[v];i;i=e[i].next)
if(!vis[e[i].to]) {
root = 0;
sum = son[e[i].to];
getroot(e[i].to,v);
solve(root);//递归处理下一个连通块
}
}
int main()
{
sum = f[0] = n;//初始化
root = 0;
getroot(1,0);//找重心
solve(root);//点分治
}
【注释】:作者是用 son[] 来表示节点x为根的子树大小,可能他人更多地是用size[]来表示,二者同意。
二、【POJ 1741 & BZOJ 1468 & BZOJ 3365】
给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K。
【题解】:
我们找到树的重心,然后dfs,求出每个点到root的距离deep,然后对deep排序,扫描哪些点对是符合的。
但是,点分治要求处理的路径是经过root,所以如果一条路径是在同一个子树之内的就不符合要求,所以还要对子树dfs一下,然后去重。
接下来处理好root后,就可以处理其他连通块了,即递归其子树。
【代码】:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 10010
#define inf 1e9+10
struct node{
int to,c,next;}g[N*2];
int head[N],m;
int son[N],f[N];
bool vis[N];
int d[N],deep[N];
int n,sum,root,k,ans;
void add_edge(int from,int to,int cost)
{
g[++m].next = head[from];
head[from] = m;
g[m].to = to; g[m].c = cost;
}
void getroot(int v,int fa)
{
son[v] = 1; f[v] = 0;
for(int i = head[v];i;i=g[i].next)
if(g[i].to != fa && !vis[g[i].to])
{
getroot(g[i].to,v);
son[v] += son[g[i].to];
f[v] = max(f[v],son[g[i].to]);
}
f[v] = max(f[v],sum - son[v]);
if(f[v] < f[root]) root = v;
}
void getdeep(int v,int fa)
{
deep[++deep[0]] = d[v];
for(int i = head[v];i;i=g[i].next)
if(g[i].to != fa && !vis[g[i].to])
{
d[g[i].to] = d[v] + g[i].c;
getdeep(g[i].to,v);
}
}
int cal(int v,int cost)
{
d[v] = cost; deep[0] = 0;
getdeep(v,0);
sort(deep+1<