【算法笔记】离线处理1

【写在前面】

有的时候,会有这种不强制离线,不带修的区间查询问题,一般考虑树状数组,线段树,主席树。

如果用树状数组或线段树,则做法往往是离线的。

【例题】

HH的项链

https://www.luogu.com.cn/problem/P1972

长度为n的序列a,m次查询,每次查询一个区间不同数字的种类数量。n,m,ai<=106

不带修,不强制在线,可以考虑离线处理+某种数据结构维护区间信息。

简单地想一想,不难明白一点:既然要统计种类数量,对于一个查询区间内的多个相同的数字,只考虑第一个。formally,对于一个区间[l,r],对于任意k,ai=k,i∈[l,r],最小的i对答案的贡献是1。

所以对于l相同的若干次查询[l,ri]可以构建一个数组b,从l开始算起,a当中第一次出现某个数的位置记为1,其余全记为0,则每次查询就是求一个区间和。树状数组就可以解决此问题。

对于很多次查询,我们把他们按照l从小到大排序,然后逐一处理。处理左端点为l的查询是,保证从l开始第一次出现的数被标记为1,后面的都标记为0。

 

采花

https://www.luogu.com.cn/problem/P4113

和上一题基本一样,但查询的是出现次数大于1的数字种类数量。

很简单,HH的项链是查询出现次数大于等于1的数的种类数,则把第一次出现的位置标为1,这一题就是把第二次出现的位置标为1。

 

采花2(我自己编的)

https://假装有超链接

还是区间查询,查询一个区间出现且只出现一次的数字种类数。

好吧,和采花那题刚好反过来

所以直接把第一题的答案算出来,然后减去第二题的答案就好了

实际上确实是这样做的,把第一次出现的位置标为1,第二次出现的位置标为-1,就解决问题了。

换个角度想,如果区间包含第一次出现的位置二不包含第二次,则这个数字对答案的贡献为1,如果包含两次出现的位置,则没有贡献。

前面两题理解了以后,可以顺便切掉这一题,思路和前面的大同小异(题解思路大多是用的莫队)

https://www.luogu.com.cn/problem/CF220B

 

CF1000F One Occurrence

https://www.luogu.com.cn/problem/CF1000F

原题链接(看我多贴心) https://codeforces.com/problemset/problem/1000/F

还是不强制在线,不带修的区间查询,还是关于“独一无二的数”。不过这次是查询一个区间只出现一次的数是啥。

 

官方题解说可以用主席树在线搞,这里先介绍普通线段树的离线做法

看完了前面三个题,不妨参考前面的思路,先想一想这道题该怎么做。如果一时半会想不起来也没关系,相信你已经有一定的思路了。

对于每一个位置,记录下一个和他一样的数字的出现位置nxt[i]。

一个区间[l,r]当中,如果x第一次出现在位置i,并且nxt[i]>r,则x在[l,r]种是一个独一无二的数。也就是说,max(l<=i<=r){nxt[i]}>r,则a[argmax(l<=i<=r){nxt[i]}]就是答案。再想一想刚才的离线方法,从左到右再线段树里面位置i标记nxt[i],用线段树查找区间最小值,查询按照l升序排列,在标记的过程中逐一查询。

posted @ 2021-04-28 13:55  LMXZ  阅读(177)  评论(0)    收藏  举报