题目
前言
树链剖分它不香吗?
Solution
这里有一个非常之玄的做法。我们将Q个操作所涉及的权值存起来,其复杂度是 O ( n + q ) O(n+q) O(n+q)哒。
有一个奇妙的预处理:首先,我们存好每个节点所涉及的权值。然后,用一个存放有用的权值的数组,边dfs边一个个统计权值出现的次数,到了某个节点就直接在节点上赋值就行了。
我们用线段树来操作。首先枚举权值(可以预处理权值和操作的对应关系)。线段树表示本节点到根节点路径上权值出现次数的变化量。
- 修改操作:若枚举的权值为原来权值,就在其子树中减去1(此节点一定在且只在子树中节点到根节点路径中),若为新权值,就加1。具体可以预处理出dfn序,siz(子树大小),更改就可以用 [ d f n [ x ] , d f n [ x ] + s i z [ x ] ] [dfn[x],dfn[x]+siz[x]] [dfn[x],dfn[x]+siz[x]]在线段树上完成。
- 查询操作:直接 a n s [ u ] + a n s [ v ] − a n s [ l c a ( u , v ) ] − a n s [ f a [ l c a ( u , v ) ] ] ans[u]+ans[v]-ans[lca(u,v)]-ans[fa[lca(u,v)]] ans[u]+ans[v]−ans[lca(u,v)]−ans[fa[lca(u,v)]]。
我们发现,单次线段树清空非常耗时。怎么办呢?我们直接将清0操作变成修改操作。(只是常数翻了一番 )
然后,就没有然后了。
Code
感觉很考码力,进不了原网站就不码了。。。相信自己!