[模板] 带修莫队
发布日期:2021-05-08 23:16:29 浏览次数:15 分类:博客文章

本文共 1371 字,大约阅读时间需要 4 分钟。

一、题目

其实是一道带修莫队的模板题啊。

二、解法

普通莫对其实是一个二维的信息 \((l,r)\),既然要支持修改,我们添加一个信息表示这个询问用到的修改是 \([1,t]\),那么我们可以用一个三维信息来表示一个询问 \((l,r,t)\)

排序的方法是这样的:先判断 \(l\) 在不在一个块内,不在一个块内就直接排;再判断 \(r\) 在不在一个块内,不在一个块内就直接排;最后按 \(t\) 从小到大排序。排完序之后直接按普通莫队的做法做就行,实现代码如下:

bool operator < (const node &b) const{	if(pos[l]!=pos[b.l]) return l

本文的重点是证明待修莫对的时间复杂度,时间消耗主要分成三个部分,设块长为 \(a\)

  • \(t\) 轴的移动时间复杂度,因为 \((l,r)\) 的组合只有 \(\frac{n^2}{a^2}\) 种,每一种的时间消耗为 \(t\),总时间复杂度 \(O(\frac{n^2}{a^2}t)\)
  • 如果 \(l,r\) 所在块相同那么 \(l,r\) 的移动复杂度为 \(O(na)\),可以看做每一个询问都在块里面乱动。
  • \(l\) 从一个块到另一个块时 \(r\) 移动的时间复杂度为 \(O(\frac{n^2}{a})\),单次是 \(O(n)\) 的乘上的块的个数。

\(a\) 一般取 \(O(n^{\frac{5}{3}})\),我习惯于把块长设为定值。还有这道板题有一个细节,就是我们要在修改处记录修改之前的权值,这样就方便回退了。

#include 
#include
using namespace std;const int M = 200005;const int sq = 2412;int read(){ int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f;}int n,m,k,ans,ln,l,r,t,res[M],cnt[5*M];int a[M],b[M],c[M],d[M],pos[M];char s[M];struct node{ int l,r,t,id; bool operator < (const node &b) const { if(pos[l]!=pos[b.l]) return l
l) del(a[l++]); while(R>r) add(a[++r]); while(R
T)//回撤t这个修改 { if(l<=b[t] && b[t]<=r) del(a[b[t]]); a[b[t]]=d[t]; if(l<=b[t] && b[t]<=r) add(a[b[t]]); t--; } res[q[i].id]=ans; } for(int i=1;i<=ln;i++) printf("%d\n",res[i]);}
上一篇:[省选前集训2021] 模拟赛4
下一篇:[模板] 多项式多点求值

发表评论

最新留言

不错!
[***.144.177.141]2025年04月08日 13时08分51秒