luogu P4178 Tree】的更多相关文章

题目链接 luogu P4178 Tree 题解 点分治 代码 // luogu-judger-enable-o2 #include<cstdio> #include<algorithm> inline int read() { int x = 0,f = 1 ; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c <= '9' && c >= '0') x…
题面 传送门:https://www.luogu.org/problemnew/show/P4178 Solution 首先,长成这样的题目一定是淀粉质跑不掉了. 考虑到我们不知道K的大小,我们可以开一个splay来统计比某个数小的数的数量. 具体做法等我开淀粉质讲解的坑再满满填(咕) Code #include<iostream> #include<vector> #include<cstdio> using namespace std; long long read…
题目大意 给定一棵树,边带权,问有多少点对满足二者间距离$\leq K$,$n \leq 40000$. 题解 点分治专题首杀!$Jackpot!$ (本来看着题意比较简单想捡个软柿子捏,结果手断了……) 点分治的总结先鸽着,这里只说题解. 分析一下题目: 对于无根树上的某一节点x,如果把它看作根,树上的路径无非两类: 1.经过x. 2.不经过x,但在它的子树里. 显然,后者利用点分治的思想经过递归处理可以转化为前者,那么我们就只需考虑第一类, 这也是点分治的强大之处. 我们设$dis[]$为节…
[题解]P4178 Tree 一道点分治模板好题 不知道是不是我见到的题目太少了,为什么这种题目都是暴力开值域的桶QAQ?? 问点对,考虑点分治吧.直接用值域树状数组开下来,统计的时候直接往树状数组里面查询.记得每一层先把这一层的答案统计一下,统计的方法就是刚刚讲的在桶里查. 问题是回溯,值域不大,所以常数还可以,但是我们最好还是开个\(temp\)把我们做修改的地方记录一下,在\(calc\)返回的时候直接回溯. 时间复杂度\(nlog^2n\) 有一些细节需要注意.比如要把\(d[]\)的先…
Tree P4178 Tree 点分治板子. 点分治就是直接找树的重心进行暴力计算,每次树的深度不会超过子树深度的\(\frac{1}{2}\),计算完就消除影响,找下一个重心. 所以伪代码: void solve(int u) { calc(u); used[u]=true; for(int i=head[u];i;i=e[i].nxt) { int v=e[i].to; if(!used[v]) { getroot(v) solve(root); } } } calc因题而异,主要靠思维.…
题目:https://www.luogu.org/problemnew/show/P4178 这道题要把 dep( dis? ) 加入一个 tmp 数组里,排序,计算点对,复杂度很美: 没有写 sort 竟然还有50分! 虽然调了很久不过第一次用对拍找出了错误! 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std…
题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式:   N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k   输出格式:   一行,有多少对点之间的距离小于等于k   输入输出样例 输入样例#1:  7 1 6 13 6 3 9 3 5 7 4 1 3 2 4 20 4 7 2 10 输出样例#1:  5 题解:点分裸题,考虑分治中的暴力,将所有的重心子树中的点到中心的距离排序,对于一组l-r之间如果…
题面要求小于等于K的路径数目,我么很自然的想到点分治(不会的就戳我) 这道题的统计答案与模板题不一样的地方是由等于K到小于等于K 那么我们可以把每一个子节点到当前根(重心)的距离排序,然后用类似双指针的方法来求小于等于K的边的数量 但是如果只是双指针统计的话,那么以下不合法的情况显然也会被算进答案: 而我们需要的合法路径是长成这样的: 所以我们需要减去上述不合法的路径,怎么减呢? 不难发现,对于所有不合法的路径,都是在当前跟的某一棵子树上的(没有跨越两个子树) 所以我们可以对当前跟节点的每一条边…
点分治 还是一道点分治,和前面那道题不同的是求所有距离小于等于k的点对. 如果只是等于k,我们可以把重心的每个子树分开处理,统计之后再合并,这样可以避免答案重复(也就是再同一个子树中出现路径之和为k的点) 但是对于这道题,如果我们还要这样求的话显然是会超时的,意外要枚举所有点的话有点勉强 ... 考虑一次把重心的子树全部遍历,统计到重心的距离,放进数组中,排序.然后我们可以用指针对撞的方法,用l,r两个指针分别从前后开始扫描. 容易发现,当指针再l的位置时,如果我们记录距离排好序的数组rd[l]…
最简单的点分治 淀粉质的思想: “分而治之”,缩小问题规模,合并求解: #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<iostream> using namespace std; #define up(i,l,r) for(register int i = (l); i <= (r); ++i) #define dn(i,l,r…