相信大家对 O(n32) 离线解决序列问题莫队算法都不陌生,在这里我要介绍一下能够兹瓷修改操作的莫队算法。
关于基本的不带修改的莫队算法,参考cty的博客:http://blog.csdn.net/alan_cty/article/details/51277499
分块大小 S 为 n23 ,那么我们就有 n13 块。
原本的莫队关键字只有两个,一个是左边界,一个是右边界。而带修改莫队要再加上一维:在第几个操作之后。
我们按照这左边界所在块、右边界所在块以及第三关键字排序(上面说的那个)。
统计答案时多维护一个指针记录修改操作执行到哪里,移动时直接修改即可,如果在区间内还要计算其对答案的影响。
左指针移动次数: O(n×n23)=O(n53) 。
右指针移动次数: O(n×n23+n13×n)=O(n53) 。
修改指针移动: O((n13)2×n)=O(n53) 。
因此总时间复杂度 O(n53) 。
题目来源[JZOJ2491]维护队列。带修改莫队裸题。
#include
#include
#include
#include
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) ch=='-'?f=-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=10005;
const int M=10005;
const int C=1000005;
const int B=250;
struct Q
{
int l,r,t,id;
}query[M];
bool operator<(Q x,Q y){return (x.l-1)/B<(y.l-1)/B||(x.l-1)/B==(y.l-1)/B&&(((x.r-1)/B<(y.r-1)/B)||(x.r-1)/B==(y.r-1)/B&&x.tstruct E
{
int x,c0,c1;
}modify[M];
int color[N],ct[N];
int n,m,qs,es,now;
int ans[M];
int cnt[C];
void add(int x){now+=!(cnt[color[x]]++);}
void erase(int x){now-=!(--cnt[color[x]]);}
void change(int x,int l,int r,bool tp)
{
int y=modify[x].x;
if (l<=y&&y<=r) erase(y);
color[y]=tp?modify[x].c1:modify[x].c0;
if (l<=y&&y<=r) add(y);
}
void Motao()
{
now=0;
int lcur=query[1].l,rcur=query[1].r,mcur=query[1].t;
for (int i=lcur;i<=rcur;i++) add(i);
for (int i=1;i<=mcur;i++) change(i,lcur,rcur,1);
ans[query[1].id]=now;
for (int i=2;i<=qs;i++)
{
while (lcurwhile (query[i].lwhile (query[i].rwhile (rcurwhile (mcur1);
while (query[i].t0);
ans[query[i].id]=now;
}
}
int main()
{
freopen("maintain.in","r",stdin),freopen("maintain.out","w",stdout);
n=read(),m=read(),qs=es=0;
for (int i=1;i<=n;i++) ct[i]=color[i]=read();
for (int i=1,u,v;i<=m;i++)
{
char cmd=getchar();
while (cmd!='Q'&&cmd!='R') cmd=getchar();
u=read(),v=read();
if (cmd=='Q') query[++qs].l=u,query[qs].r=v,query[qs].t=es,query[qs].id=qs;
else modify[++es].x=u,modify[es].c0=color[u],color[u]=modify[es].c1=v;
}
for (int i=1;i<=n;i++) color[i]=ct[i];
sort(query+1,query+1+qs);
Motao();
for (int i=1;i<=qs;i++) printf("%d\n",ans[i]);
fclose(stdin),fclose(stdout);
return 0;
}