支(zi)持(ci)修改的莫队算法

Preface

相信大家对 O(n32) 离线解决序列问题莫队算法都不陌生,在这里我要介绍一下能够兹瓷修改操作的莫队算法。

Basis

关于基本的不带修改的莫队算法,参考cty的博客:http://blog.csdn.net/alan_cty/article/details/51277499

Algorithm

分块大小 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 <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>

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.t<y.t);}

struct 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 (lcur<query[i].l) erase(lcur++);
        while (query[i].l<lcur) add(--lcur);
        while (query[i].r<rcur) erase(rcur--);
        while (rcur<query[i].r) add(++rcur);
        while (mcur<query[i].t) change(++mcur,lcur,rcur,1);
        while (query[i].t<mcur) change(mcur--,lcur,rcur,0);
        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;
}

你可能感兴趣的:(OI,莫队算法)