[NOIP] [LCA] NOIP2016Day1 天天爱跑步

题目传送门
讲真,第一眼看上去以为是水题……
于是一发一共能观测到多少人就上去了……
然后极其黑历史,成就达成第一次看错题......
请各位注意,输出每个节点的观察员可以看到多少人!!!
然后怎么做……
因为每个人走的是最近路径,因此每个人走的路径应为 S>lca(S,T)>T ,这样,每个人的路径就可以分为两段, S>lca(S,T) lca(S,T)>T 了。
那么, x 节点的观测者能观测到什么呢?
对于 x 节点,既可以通过后向儿子走,也可以向父亲走,也就是 x 落在 S>lca(S,T) 上或落在 lca(S,T)>T 上。
那么, x S>lca(S,T) 上时,满足 dep[x]+w[x]=dep[S]
x lca(S,T)>T 上时,满足 dep[x]w[x]=dep[T]len(S,T)
这样其实就是统计满足上述等式的点的个数,因为每次都是对 x 的子树的操作,所以可以树链剖分,用差分数组维护。但是复杂度我猜 O(mlog22n) ,卡常可以玩玩……
放弃树剖,发现一个性质,如果利用深搜,当 x 点退出时,其子树都已经维护完成了……
这不废话吗?
利用这点,可以开两个桶,分别为向上的(父亲)和向下的(儿子)。统计一个深度的节点个数。
So,怎么统计这两个桶……
做到 x 节点时,向下的桶加从 x 点出发人数(统计儿子),向上的桶加到 x 处结束人数。然后向下搜儿子。统计答案。
如果这样的话,答案会偏大。
当dfs过程将 lca(S,T) 退出时, ST 对答案的影响已经结束,将向下桶里 S 深度减一个,将向上 dep[T]len(S,T) 深度减一个。如果这是一条链,该点答案减一(否则会计算重复)。
因为一定要求LCA,所以可以倍增求也可以Tarjan法求,用倍增是 O((n+m)log2n) 的,Tarjan是 O(n+m) 的。
Code

你可能感兴趣的:(NOIP,树上倍增)