分散层叠算法学习笔记
更好的阅读体验
前言
分散层叠算法,英文为Fractional Cascading,可以以优秀的时空复杂度在线计算出某个值在若干个序列中后继。
Fractional意为分散的,Cascading意为阶梯式渗透,而Fractional Cascading本质上就是对于若干个有序信息分散开,然后一层层渗透,然后得到最后的结果。
模板
P6466 分散层叠算法(Fractional Cascading)
给定
注意,下面的后继都指的是非严格后继。
首先有一个很简单的时间
还有一种做法是时间
考虑综合两个方法分别的优势,得到更优秀的做法。
设
-
-
- 归并排序的同时,顺便维护出
b_i 中每个元素在a_i,b_{i+1} 中的后继pos,lst 。
不难得到
查询的时候,我们在
考察
那么我们直接暴力检查
以此类推,查询的总复杂度为
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=20005,maxk=105;
int n,k,q,d,lastans;
int a[maxk][maxn],len[maxk],c[maxn];
struct node{
int val,pos,lst;
}b[maxk][maxn],tmp[maxn];
int main(){
scanf("%d%d%d%d",&n,&k,&q,&d);
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
len[k]=n;
for(int i=1;i<=n;i++)
b[k][i].val=a[k][i],b[k][i].pos=i,b[k][i].lst=0;
for(int i=k-1;i>=1;i--){
for(int j=2;j<=len[i+1];j+=2)
tmp[j/2]=b[i+1][j],tmp[j/2].lst=j;
int ptmp=1,plst=1;
for(int j=1;j<=n;j++){
while(ptmp<=len[i+1]/2&&tmp[ptmp].val<=a[i][j])
len[i]++,b[i][len[i]]=tmp[ptmp],b[i][len[i]].pos=j,ptmp++;
while(plst<=len[i+1]&&b[i+1][plst].val<a[i][j])
plst++;
len[i]++,b[i][len[i]].val=a[i][j],b[i][len[i]].pos=j,b[i][len[i]].lst=plst;
}
while(ptmp<=len[i+1]/2)
len[i]++,b[i][len[i]]=tmp[ptmp],b[i][len[i]].pos=n+1,ptmp++;
}
for(int i=1;i<=len[1];i++)
c[i]=b[1][i].val;
for(int i=1;i<=q;i++){
int x,pos;
scanf("%d",&x),x^=lastans,pos=lower_bound(c+1,c+len[1]+1,x)-c;
lastans=0;
for(int i=1;i<=k;i++){
if(pos>1&&b[i][pos-1].val>=x)
pos--;
if(pos<=len[i])
lastans^=a[i][b[i][pos].pos],pos=b[i][pos].lst;
else pos=len[i+1]+1;
}
if(i%d==0)
printf("%d\n",lastans);
}
return 0;
}
扩展
在一个每个点度数不超过
不难发现模板的内容是DAG是一条链的情况。
该问题的解法法类似于模板,考虑在拓扑排序中每遇到一个
此时点
把所有
等比数列求和可得
于是这个做法的时间复杂度为
本质
实际上,上文中提取
我们考虑对于若干个序列进行分散层叠时,可以从每个序列提取
应用
例题1
区间加,区间查询一个数
首先考虑一个很简单的做法:枚举每个块,在块内二分出小于
序列分块,设块长为
对于第一层的整块,询问直接合并分散层叠(复杂度为
对于第一层的散块(同时也是第二层的整块)暴力建分散层叠可以做到
对于第二层的散块跑暴力,复杂度为
总体复杂度为
经过计算可得
这种方法复杂度可以更小,但是没有实际意义了。
我们发现上面的方法是分块上分块的结果,于是很自然地想到分更多层,即利用线段树的结构进行更多层分块。
我们对
对于区间修改,仍然采用整块打标记散块重构的方式,不难发现散块重构需要修改散块对应节点到线段树根节点这条路径的所有点代表的序列,序列长度之和为
对于区间查询,我们在根节点二分出位置,然后暴力递归儿子,由于线段树的结构,共有
当
例题2
区间加,区间查询第
即P5356 [Ynoi2017] 由乃打扑克。
例题3
区间加,单点修改,区间查询最大值小于等于值
即P6578 [Ynoi2019] 魔法少女网站。
例题4
区间加,区间查询最大子段和。
即P4118 [Ynoi2018] 末日时在做什么?有没有空?可以来拯救吗?。
后记
分散层叠算法适用于在线算法时间复杂度的平衡以及空间复杂度的减小,在分块问题上有着广泛的应用,其思想也应用在了range tree,跳表等算法/数据结构中,但劣势是实现的细节过多。
所以做分散层叠口胡就行了,比赛还是用别的方法吧。