差分之间,性质多多——差分综合应用学习笔记

本文介绍了差分技巧在解决区间修改及区间查询问题中的应用,并通过三个具体实例详细讲解了如何利用差分技巧简化问题,包括序列统一操作计数、树上路径深度求和及其变形问题。

差分,能够巧妙地维护多种区间修改,将区间修改转化为单点修改,将询问转化为前缀查询。

但是,差分能支持的,岂止是这些。有时,差分一下,性质多多。

例1. [Luogu P4552]IncDec Sequence

Description

给定一个序列,请求出至少需要多少次区间统加111或区间统减111的操作才能使得整个序列中的数两两相同。

为了增加难度,你也需要求出,在满足操作次数最小且最终序列中的数两两相同的前提下,最终能够得到多少种不同的序列。

Solution

本题中有区间修改这一说。不难想到差分。

现在,我们完成了一个重要的转化: 给定一个长度为n+1n+1n+1的序列,每次可以选择序列中的任两个位置,一个加111,另一个减111,使得这个序列的第2−n2-n2n个位置均为000

由于我们要让操作次数尽可能得小,我们要先贪心地去选择在[2,n][2,n][2,n]区间内的一个正数和一个负数并将它们配对,正数减111,负数加111。经过了这些操作之后,我们再将剩下的数去与1,n+11,n+11,n+1中的一个数配对。假设这个数为正,那么配对之后它一定要减111;否则一定要加111。经历这些操作之后,我们便完成了要求。

假设2−n2-n2n这些数中,正数之和为xxx,负数的绝对值之和为yyy。首先,我们使用了min(x,y)min(x,y)min(x,y)次操作,每次操作将一个正数减111,一个负数加111。然后,我们使用了max(x,y)−min(x,y)max(x,y)-min(x,y)max(x,y)min(x,y)次操作,将每一个[2,n][2,n][2,n]区间内不为000的数与下标为111n+1n+1n+1中的一个数配对。于是我们总共使用了max(x,y)max(x,y)max(x,y)次操作。由于第一个位置有max(x,y)−min(x,y)+1max(x,y)-min(x,y)+1max(x,y)min(x,y)+1种不同的值(即,对于剩下的max(x,y)−min(x,y)max(x,y)-min(x,y)max(x,y)min(x,y)都可以与下标为111的位置配对或不与它配对),所以两个答案分别为:

max(x,y)max(x,y)max(x,y)
max(x,y)−min(x,y)+1max(x,y)-min(x,y)+1max(x,y)min(x,y)+1

时间复杂度O(n)O(n)O(n)。本题得到完美解决。

Summary

我们通过差分,将区间修改转化为单点修改,自然而然得到了几个性质,从而推出结论。

例2. [LNOI2014]LCA

Description

给定一棵包含nnn个节点的树,qqq次询问,每次给定l,r,xl,r,xl,r,x,请你求出∑i=lrdepth(LCA(i,x))\sum_{i=l}^r depth(LCA(i,x))i=lrdepth(LCA(i,x))

这里的depthdepthdepth表示一个节点的深度,即其与根节点的距离111

Solution

一道绝妙的好题。

首先,我们考虑depth(LCA(i,x))depth(LCA(i,x))depth(LCA(i,x))等于什么。在这之前,我们先思考depthdepthdepth表示什么,以及LCALCALCA表示什么。

depthdepthdepth: 一个节点到根节点的深度加1
也就是说,从这个节点开始往上走,一直走到根,期间经过的点的数量

LCALCALCA: 两个节点的最近公共祖先。
也就是说,从这两个节点中的一个往上走,对每一个经过的点打上标记;然后另外一个节点也向上走,如果遇到了一个打上标记的节点,立即将这个节点作为它们俩的LCA

综上所述,depth(LCA(i,x))depth(LCA(i,x))depth(LCA(i,x))就等价于: 让iii不停地往上走,对每一个走到的节点打上标记,即将该点的点权加111;然后再让xxx往上走,标记的总数量(即点权之和)就是depth(i,x)depth(i,x)depth(i,x)

于是,∑i=lrdepth(LCA(i,x))\sum_{i=l}^r depth(LCA(i,x))i=lrdepth(LCA(i,x))也可以通过类似上述方法来求出。


首先,本题的询问似乎很难处理,而且询问也没有强制在线,于是我们考虑离线。同时,我们再将一个询问拆成两个询问,即查询[1,r][1,r][1,r][1,l−1][1,l-1][1,l1],二者相减即可。

然后,我们对于现在的2m2m2m个询问从小到大排序。每次加入一个新节点,就将它到根节点的路径上所有节点的点权都加111;对于每一次询问,查询它到根节点路径上每个节点的点权之和。这相当于“路径修改,路径查询”,可以通过重链剖分套线段树在O(qlog⁡2n)O(q \log^2 n)O(qlog2n)的代价下搞定。

总时间复杂度O(n+qlog⁡2n)O(n+q \log^2 n)O(n+qlog2n)。注意取模即可。

Summary

有时,区间查询可以转化为更容易处理的前缀查询,方便我们“莫队”离线处理。同时,本题也考察了树链剖分,是一道不可多得的LNOI好题。

例3. [GXOI/GZOI2019]旧词(改编)

Description

给定一棵包含nnn个节点的树和一个常数k(1≤k≤109)k(1≤k≤10^9)k(1k109)qqq次询问,每次给定l,r,xl,r,xl,r,x,请你求出∑i=lrdepth(LCA(i,x))k\sum_{i=l}^r depth(LCA(i,x))^ki=lrdepth(LCA(i,x))k

这里的depthdepthdepth表示一个节点的深度,即其与根节点的距离111

由于答案可能很大,请将其对998244353998244353998244353取模。

Solution

我们仍然将每一个询问拆成两个,离线下来排序。但是k≠1k≠1k=1似乎很难办……而且kkk这么大,二项式定理拆开都不行……

别慌,我们考虑能不能通过一步差分,将本题转化为例2。定义Ai=(depthi+1)k−depthikA_i=(depth_{i}+1)^k-depth_{i}^kAi=(depthi+1)kdepthik,对于新加入的一个节点,从它到根节点的路径上每个节点都加上一个AiA_iAi;对于一次查询,仍然查询它到根节点的路径上所有节点的点权之和。我们可以处理出AAA的前缀和,然后通过树剖套线段树求出。

这种做法为什么是正确的呢?根据差分的性质,从一个节点到根节点的路径上求出点权之和,就是这个节点本身的贡献之一。于是,每次查询我们都能得到正确的答案。

总时间复杂度仍然为O(n+qlog⁡2n)O(n+q \log^2 n)O(n+qlog2n)

一些练习题

①P6070
先挖一个比较显然的性质,然后直接二分差分即可。

②[ABC155F]Perils in Parallel
一道套路题,通过差分可以转化为单点修改,然后建图乱搞即可。

③P3620
一道经典题,通过差分进行等效转化即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值