CF1764H 题解
题意
给定长为 $n$ 的序列,初始 $a_i=i$。有 $m$ 个操作,操作为给出 $l_i,r_i$ 并将 $[a_{l_i},a_{r_i}]$ 赋值为 $a_{l_i}$。要求对每个 $[i,i+k-1]$,回答保留该区间内的操作后序列中不同元素的数量。
初步分析
不难发现,对答案产生贡献的有两种情况:
没有被执行操作的元素
某次操作左端点的元素
我们尝试分别统计这两种情况。
只考虑维护序列,我们容易想到一种基于均摊的,用 set 暴力维护的做法:在 set 中存下每一个区间,遇到修改操作就找到左右端点所在的 set 区间并将其分裂,暴力删去左右端点之间的区间,插入新区间。
我们想在上述过程中同时预处理我们需要的东西。
进一步分析
对于第一种情况:我们对 set 中的每个区间同时记录下一个 $time$,表示这个区间最初是第 $time$ 次修改操作插入进去的。假设当前是第 $i$ 次修改操作,将从 set 中删去 $[l,r]$ 这个区间,那么我们可以知道在 $[time+1,i-1]$ 这个时间段以内 $[l,r]$ 是没有被修改过的,可以作为第一种贡献。贡献的范围是所有 $ql>time\and qr<i$ 的询问操作。这是一个经典的二维数点问题,可以用扫描线+树状数组解决。
对于第二种情况:我们需要对每个操作维护 $3$ 个信息,分别是:$pre_i$,该操作之前最后一个覆盖到 $l_i$ 的操作;$go_i$,该操作的原始区间 $[l_i,r_i]$ 被完全覆盖掉的时刻;$ed_i$,该操作彻底不能产生贡献的时刻。如果维护好了这些信息,我们知道这个操作能对 $pre_i<ql\and qr<ed_i\and ql\le i\le qr$ 的询问产生贡献,这同样是一个二维数点问题。
具体的,$pre_i$ 只需要在 set 中插入该操作之前查询即可;$go_i$ 为所有 $time=i$ 的区间中被删去时刻的最大值;$ed_i=\max (go_i,ed_j[pre_j==i])$。
这样这道题就完全解决了。
代码实现
感觉只有必要放一下预处理,都来做这题了不至于不会二维数点吧:
1 | struct bignod{ |