思路讲解

AC代码
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=78683868
1 | // by Gospel_rock |
心路历程(WA,TLE,MLE……)
这个循环退出条件特别容易忘记。
1 | function<void(ll,ll,ll,ll)> dfs=[&](ll a,ll b,ll c,ll d){ |

https://ac.nowcoder.com/acm/contest/view-submission?submissionId=78683868
1 | // by Gospel_rock |
这个循环退出条件特别容易忘记。
1 | function<void(ll,ll,ll,ll)> dfs=[&](ll a,ll b,ll c,ll d){ |
题目大意
给定一棵包含 2n 个节点的树,树上分布着 n 种钥匙(编号 1 到 n)和 n 种锁(编号 1 到 n)。每种钥匙和每种锁在树上恰好出现一次。
节点信息由数组 a 给出:
若 ai>0,表示该节点拥有编号为 ai 的钥匙。
若 ai<0,表示该节点拥有编号为 −ai 的锁。
移动与收集规则
出发点:必须选择一个拥有钥匙的节点作为起点。
钥匙获取:到达(或经过)拥有钥匙的节点时,自动获得该钥匙。钥匙永久保留。
通行限制:只有当手中拥有编号为 k 的钥匙时,才能进入拥有编号为 k 的锁的节点。
目标
对于每一种钥匙 i(1≤i≤n),判断:如果从拥有钥匙 i 的节点出发,是否能够遍历树的足够多部分,从而收集到全部 n 种钥匙。
输入格式
第一行包含整数 T,表示测试数据组数。
每组数据包含:
输出格式
对于每组数据,输出一个长度为 n 的 01字符串。
字符串第 i 个字符对应编号为 i 的钥匙作为起点的结果。
若能收集所有钥匙输出 1,否则输出 0。
样例
1 | Input |
样例解释(以第二组数据为例)

判定过程:
最终输出:011。
首先,我们想到暴力,但是跑一次只需要 O(n),也要 O(n2) 才能跑完。
于是面对这种复杂的问题,我们想到,需要分而治之。
我们先想,如果只有一个钥匙和一个门,那么合法的点在哪里那?

不难发现,肯定是在这边半颗树,也就是有钥匙的子树上的点才是合法的。
那么这个结论是非常显然的,那么现在问题在于我们有非常多的门,其实我们运用一下这个结论就会发现,我们只要不断往门上含有钥匙的子树上走,就行了,最后我们会得到一个联通块,检查一下这个联通块的联通性即可。
https://vjudge.net/solution/64200130
1 | // by Gospel_rock |
那么一开始,我们选择的是纯 dfs 解决该问题,但是 WA 了。
1 | vll valid; |
主要原因是使用 dfs 时,没有一个全局的信息来参考。
比如下面这组 hack 数据,我的程序会错误地把 2,3 加入 valid 数组中,这个显然是有问题的。
这个其实是因为我们先走了节点 3 这条支路,又走了节点4。

于是我们继续在想,用树上差分固然可以解决此问题,但是总觉得有点杀鸡用牛刀了。使用纯 dfs 方案用办法解决此问题吗?
我们发现这个问题在于我们走完一条路了以后,我们需要知道这条路是封闭的,还是会继续往下走的?其实只要是会继续往下走的,其他路也不需要走了。
知道了这个以后,我们发现,其实不用改动很多,仅仅只需要加一个返回值,子树返回值为 1 时,我们直接开摆即可。
1 | // return 1 表示的是可以往下走 |
然后就 AC 了。
P2880 [USACO07JAN] Balanced Lineup G
用树状数组RMQ。
https://acm.hdu.edu.cn/contest/view-code?cid=1177&rid=12260
1 | // by Gospel_rock |
1和n的超距作用。
https://acm.hdu.edu.cn/contest/view-code?cid=1177&rid=12203
1 | FOR(i,1,N){ |
【莫队算法【力扣双周赛 162】】 https://www.bilibili.com/video/BV1p3h3zYEbc/?share_source=copy_web&vd_source=6ca0bc05e7d6f39b07c1afd464edae37
看视频吧,以我的理解
https://leetcode.cn/problems/threshold-majority-queries/submissions/649553401/
1 | #include <algorithm> |