尝试学习 Min_25 筛,看了半天最终弃疗……
来写点 DS 题散心。
题面中二程度爆表。
以下 ai=ki。
翻译一下,题目的意思是:
对于每个有序数对 (x,y),x<y,如果 ax,ay>y−1maxi=x+1ai,对答案产生 p1 的贡献;如果 ax>y−1maxi=x+1ai>ay 或 ay>y−1maxi=x+1ai>ax,对答案产生 p2 的贡献。
询问给定 l,r,求两个数都在 [l,r] 内的数对的答案。
两种贡献都跟 max 有关,所以我们可以考虑对于这个 max 统计答案的贡献。
先不考虑多组询问,假设只求整个序列的答案。
设 lefti 表示 [1,i) 中最后一个 >ai 的数的位置,righti 表示 (i,n] 中第一个 >ai 的数的位置。
这个东西随便用单调栈/双向链表/set 预处理就好了。
对于每个 i,显然 ai=righti−1maxi=lefti+1。
所以 (lefti,righti) 产生 p1 的贡献。
(lefti,j),(k,righti),i<j<righti,lefti<k<i 产生 p2 的贡献。
现在来考虑多组询问。
这个时候发现我们没辙了。
考虑离线。
对于第一种贡献,我们把询问按 r 排序,从 1→n 扫描,如果遇到一个位置 i,并有另外一个/多个位置 j 满足 i=rightj,就让数据结构上第 leftj 个数加上 p1。
然后对于所有 r=i 的询问,查询数据结构上 [l,r] 的和,即为第一种贡献。
注意这样子没法统计到形如 (x,x+1) 的数对的贡献,另外加上即可。
对于第二种贡献,我们先考虑 (lefti,j),i<j<righti 的情况,另一种倒过来即可。 把询问按 l 排序,从 n→1 扫描,遇到一个位置 i,并有 j 满足 i=leftj,就让数据结构上 [j+1,rightj) 加上 p2。
对于 l=i 的询问,直接查询 [l,r] 区间和。
数据结构用线段树就好了。
因为个人习惯,我顺便写了动态开点和标记永久化。
代码:
1 |
|