Codeforces 1000F

原题链接

题意

给定1个长度为\(n\)的静态序列,\(q\)次询问\([l_i,r_i]\)恰好出现1次的数(输出任意1个即可);若不存在仅出现1次的数,则输出0。\(1 \leq a_i,n,q\leq 5 \times10^5\)

题解

首先考虑求解区间内仅出现1次的数的个数。

有1种不错的思路是,既然仅出现1次的元素才能计入答案,则不妨令各类元素的第1个贡献为1,第2个贡献为-1,其余不贡献,则区间和即为恰好出现1次的元素种数。(这种思路的本质是通过拆分/后悔操作解决区间限制问题,差分也是同理)。

但对于多组询问,元素的贡献也是动态的;考虑有序地处理:仅\(l_i\)会影响各位置的贡献,故将询问按\(l_i\)从小到大排序,则每次\(l_i\)移动时只需修改同类元素向后两位的贡献。单点修改,区间求和,基于位置的线段树即可维护。

再考虑求出任意1个\([l_i,r_i]\)内恰好出现1次的数。

如果延续上文的思路,则应查找出1类在\([l_i,r_i]\)中出现\(1\)的贡献且未出现\(-1\)的贡献的数。

这看上去需要建立基于权值的线段树,但这又无法解决位置限制的问题。与上文矛盾。

考虑维护另外1些基于位置的信息。按照“位置”的表达方式转换限制,即查找出1个位置\(pos\),使\(a[pos]\)\([l_i,n]\)中第1次出现,且\(next[pos](即后1个同类元素的位置)> r_i\)

故在基于位置的线段树上维护\(next\)及其最大值\(nextmax\),即可通过线段树的区间查询,在\(logn\)的时间内求解任意1个\(next > r_i\)的位置。

顺便地,本题实际询问是否存在符合条件的数(而不是个数),判断\(nextmax\)是否大于\(r_i\)即可。

时间复杂度\(O(nlogn)\)。[代码见此](https://github.com/littlewyy/OI/blob/master/cf 1000f segment tree)

回顾与思考

拆分操作;离线有序处理;主动维护其它信息。

另解

莫队?跑去开坑了。

posted @ 2019-05-24 19:39  littlewyy  阅读(258)  评论(0编辑  收藏  举报