CF1540D Inverse Inversions 题解

Description

传送门

Solution

算法一

考虑一个 O ( n q ) O(nq) O(nq) 的算法。

我们动态地维护序列 a a a,其中 a i a_i ai 表示 p i p_i pi [ 1 , i ] [1,i] [1,i]第几小的。显然,有 a i = i − b i a_i=i-b_i ai=ibi

对于一次修改,直接 O ( 1 ) O(1) O(1) 地更新 a i a_i ai
对于一次查询,令 a n s = a i ans=a_i ans=ai,并从 i + 1 i+1 i+1 一直扫描到 n n n。若当前的 a n s ans ans 满足 a n s ≥ a j ans \ge a_j ansaj,那么就将 a n s ans ans 加上 1 1 1,否则不做操作。这里加 1 1 1 的实质是,由于 j > i j>i j>i p j p_j pj [ 1 , j ] [1,j] [1,j]从小到大的排名 [ 1 , j − 1 ] [1,j-1] [1,j1] p i p_i pi 的排名要高,所以 p j < p i p_j<p_i pj<pi;此时,我们在 [ 1 , j − 1 ] [1,j-1] [1,j1] 的排名列表中在 i i i 之前插入了一个位置,需将 a n s ans ans 加上 1 1 1 表示 i i i [ 1 , j ] [1,j] [1,j] 中的排名。

ans=a[i];
for (int j=i+1;j<=n;j++)
  if (ans>=a[j])  ans++;

最后输出 a n s ans ans 即可。

算法二

看到时限为 5.00s \text{5.00s} 5.00s n , q ≤ 1 0 5 n,q \le 10^5 n,q105,根据 Codeforces \text{Codeforces} Codeforces 的做题经验,这显然是一道分块题(或者是一道树套树)。

考虑分块,令块长为 B B B

对于每一个块,我们维护出一个列表 v v v。其实际意义是,若进入这个块时 a n s = x ans=x ans=x,那么最终从这个块出来 a n s = v x + x ans=v_x+x ans=vx+x

每次修改都是单点的,我们更新 a i a_i ai 并重构该块的列表 v v v
对于第一次查询,我们从左往右扫描,对于零散块直接在 a a a 中扫描并更新 a n s ans ans,对于整块直接调用列表更新 a n s ans ans

显然,每次查询都是 O ( B + n B ) O(B+\frac n B) O(B+Bn) 的。关键在于,如何快速重构某一块的列表。

为方便叙述,令该块为 [ L , R ] [L,R] [L,R]。考虑从前往后扫描,实时维护一个数据结构,里面存储了若干个三元组 ( l , r , c ) (l,r,c) (l,r,c),表示将 v ∈ [ l , r ] v \in [l,r] v[l,r] 从块头推到当前位置时的值 v + c v+c v+c。每次更新的时候,我们通过二分找到 set \text{set} set 里面第一个满足 L ≤ a i L \le a_i Lai 的位置,并将该处的 ( l , r , c ) (l,r,c) (l,r,c) 段成 ( l , L − 1 , c ) (l,L-1,c) (l,L1,c) ( L , R , c + 1 ) (L,R,c+1) (L,R,c+1),将后者向后面一个 ( l , r , c ) (l,r,c) (l,r,c) 合并。接着,对于该位置往后的那一段后缀,将 c c c 全部加一。显然,这个数据结构需要维护单点查询,单点插入与区间加,采用平衡树即可。由于最多有 log ⁡ n \log n logn 个区间,所以单次重构是 O ( B log ⁡ B ) O(B \log B) O(BlogB) 的。

总复杂度 O ( q ( B + n B + B log ⁡ B ) ) O(q(B+\frac n B+ B \log B)) O(q(B+Bn+BlogB))。当 n = 1 0 5 , q = 1 0 5 n=10^5,q=10^5 n=105,q=105 时,取 B = 120 B=120 B=120 理论最优,实际应将 B B B 调小(平衡树的常数很大)。

值得一提的是,若不维护若干个三元组,而用线段树维护长度为 n n n 的序列,那么复杂度就是 O ( q ( B + n B + B log ⁡ n ) ) O(q(B+\frac n B+B \log n)) O(q(B+Bn+Blogn)),理论劣于上面的解法。但是,线段树常数较小,所以其实二者差不太多。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值