[POJ1741]Tree(点分治模板)


传送门

良心解析

其实以前在求某段序列上的区间统计问题时就碰到过类似于这样的思想。

当时的区间统计问题思路大致是这样:

选取一个点作为中间点,从这个点的左边和右边统计出满足条件的点对。然后当前的中间点就可以删去了,接着递归统计左右两个区间的方案数。

其实这就是个分治和分类讨论的思想。

满足要求的解无非就是这两种:

1.区间包含中间点(也就是两端点在中间点的左右两边)

2.区间不包含中间点(也就是两个端点都在中间点的左边或右边)

所以正确性显而易见

淀粉质就是把这种思想应用于树上的路径统计上,选取一个点作为根,然后统计经过这个点的路径数,端点一定是在子树中的,

不过这会遇到一个问题,就是两个端点会在同一颗子树中,这就需要再统计子树中的答案再减去。接着再递归求解每一颗子树。

最后一个问题就是根节点的选取,需要选重心,防止出现链导致时间复杂度退化的情况。

其次是统计答案的方法,对于此题来说有个神奇的nlogn的方法,上面的链接中已经给出。

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 100001#define INF ~(1 << 31)using namespace std;int n, K, cnt, root, tot, ans;int head[N], to[N], nex[N], val[N], f[N], size[N], deep[N], d[N];bool vis[N];//f[i]表示节点i的最大子树的大小//deep[i]表示节点i到根的距离 //vis[i] == 1 表示该节点删除 inline int read()inline void add(int x, int y, int z)//获取当前块的重心 inline void getroot(int u, int fa)f[u] = max(f[u], tot  size[u]);if(f[u] < f[root]) root = u;}//获取当前块中所有的点到根的距离 inline void getdeep(int u, int fa)}//求解经过当前根的满足条件的路径的方案数 inline int cal(int u, int now)//递归求解每一块 inline void work(int u)}int main()tot = n;f[0] = INF;getroot(1, 0);work(root);printf("%d\n", ans);}return 0;}

  



上一篇:[luoguP2157] [SDOI2009]学校食堂Dining(状压DP)

下一篇:[Vijos1308]埃及分数(迭代加深搜索 + 剪枝)


模板 点分治
Copyright © 2002-2019 k262电脑网 www.k262.cn 皖ICP备2020016292号
温馨提示:部分文章图片数据来源与网络,仅供参考!版权归原作者所有,如有侵权请联系删除!QQ:251442993 热门搜索 网站地图