区间询问凶器——莫队算法~

来源:互联网 发布:ecshop 数据库字典 编辑:程序博客网 时间:2024/06/10 03:47

莫队算法是处理区间询问问题的一类杀器。
但事实上处理区间询问问题有另一个杀器。
分sqrt(n)块,预处理ans[i][j]表示第i块到第j块的答案。
询问区间[l,r],会空出不超过O(sqrt(n))个冗余元素。暴力计算这些元素的贡献就行了。

只能解决:离线的静态的区间查询问题

只能用于:如果根据[l,r]可以O(1)||O(lgn)时间复杂度可以得到临近区间时候

大牛曾经说过(一般莫队能做的,分块+可持久化线段树 || 可持久化块状链表都是能做的)Orz Orz

辣么什么是莫队?

莫队实现了从 [l1,r1] 的询问到 [l2,r2] 的询问只需要 |l1-l2|+|r1-r2| 次基本操作就可以完成的思想

  1. 莫队区间处理方式,两种方法,一种是直接分成 sqrt(n)块,分块排序。
  2. 另外一种是求得曼哈顿距离最小生成树,根据 manhattan MST 的 dfs 序求解。

为啥要分成sqrt(n)块(先不考虑为什么分成这么多块)假设分成k块(排序是按照左端点在块内按照R排序否则按照块排序);

  • m次询问都在一块时 端点最多变化m每次最多变化n/m 2.端点最多变化m次每次最多变化n/k;所以总时间复杂度O(max(n, m*(n/k)));
  • m次询问最多的分散快外时左右端点最多变化n,总共最多k次快外询问时间复杂度O(n*k)
  • m一般情况等于n所以均衡一下n(n/k) == nk —>> k == sqrt(n);;;;

困扰如此久的时间复杂度终于明白了(感谢艾神,1神)

int n, m, lim, i, l, r, ans[]; struct Q{int l, r, id;}q[]; int cmp(const Q&a, const Q&b){return pos[a.l] == pos[b.l] ? a.r < b.r : pos[a.l] < pos[b.l];} int main(){     scanf(”%d %d”,&n,&m);     lim = ceil(sqrt(n));     for(i=1;i<=n;i++)        pos[i]=(i−1)/lim+1;    for(i=1;i<=m;i++)        scanf();     sort(q+1,q+m+1,cmp);     for(i=l=1,r=0;i<=m;i++)    {         int L=q[i].l,R=q[i].r;         if(r<R)        {            for(r++;r<=R;r++)                add(r,1);                r−−;        }         else if(r>R)            for(;r>R;r−−)                add(r,-1);         if(l<L)            for(;l<L;l++)                add(l,-1);         else if(l>L)        {            for(l−−;l>=L;l−−)                add(l);            l++;        }         ans[q[i].p]=now;     }     for(i=1;i<=m;i++)        printf(”%d\n”,ans[i]);}

曼哈顿生成树~

0 0
原创粉丝点击