数树数

题目

在这里插入图片描述

前言

    树链剖分它不香吗?

Solution

    这里有一个非常之玄的做法。我们将Q个操作所涉及的权值存起来,其复杂度是 O ( n + q ) O(n+q) O(n+q)哒。

    有一个奇妙的预处理:首先,我们存好每个节点所涉及的权值。然后,用一个存放有用的权值的数组,边dfs边一个个统计权值出现的次数,到了某个节点就直接在节点上赋值就行了。

    我们用线段树来操作。首先枚举权值(可以预处理权值和操作的对应关系)。线段树表示本节点到根节点路径上权值出现次数的变化量。

  1. 修改操作:若枚举的权值为原来权值,就在其子树中减去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]]在线段树上完成。
  2. 查询操作:直接 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

感觉很考码力,进不了原网站就不码了。。。相信自己!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值