【JZOJ 4594】 Dynamic len &【JZOJ 2491】维护队列(带修改的莫队算法 模板)

Description

有n个数编号从0→n-1,两种操作:
Q L R:询问编号为L→R-1的数中共有多少种不同的数
M X Y:将编号为X的数改为Y
共有m个操作

Analysis

此题,可以用高大上的树套树,亦可以用神奇的 JohnBer 大法。
当然,更可以用神奇的待修改的莫队算法(rzO莫队Orz)
这是本蒟蒻第一次接触莫队,顺便接触了带修莫队。
关于莫队算法,具体的网上很多都有,可以去找。
当然,对于莫队的实质,是Manhattan距离最小生成树。
分块的思路看看根据莫队的实质能不能优化,这应该是以后莫队优化的研究方向。
代码实现是有技巧的,可以把update和change写成函数。
当然,莫队的实现细节非常多,所以打起来一定要细心。

Code

这个代码可以作为带修莫队的模板

#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
using namespace std;
const int N=50010,M=1000010;
int n,m,ans,size,lyd[N],a[N],pos[N],val[N],c[M];
bool bz[N];
char ch;
struct Op
{
    int l,r,k,pos;
}b[N];
struct modifyOp
{
    int y,x,z;
}d[N];
bool cmp(Op a,Op b)
{
    return pos[a.l]<pos[b.l] || pos[a.l]==pos[b.l] && pos[a.r]<pos[b.r]
    || pos[a.l]==pos[b.l] && pos[a.r]==pos[b.r] && a.k<b.k;
}
void update(int i)
{
    if(!bz[i])
    {
        if(++c[a[i]]==1) ans++;
    }
    else
        if(--c[a[i]]==0) ans--;
    bz[i]^=1;
}
void change(int x,int y)
{
    if(bz[x])
    {
        update(x);
        a[x]=y;
        update(x);
    }
    else a[x]=y;
}
int main()
{
    freopen("len.in","r",stdin);
    freopen("len.out","w",stdout);
    int _,l,r,k;
    scanf("%d %d",&n,&_);
    size=ceil(pow(n,1.0/3));
    size*=size;
    fo(i,1,n) scanf("%d",&lyd[i]),a[i]=lyd[i],pos[i]=(i-1)/size;
    scanf("\n");
    int m=0,num=0;
    fo(i,1,_)
    {
        scanf("%c %d %d\n",&ch,&l,&r),l++;
        if(ch=='Q') b[++m].l=l,b[m].r=r,b[m].pos=m,b[m].k=num;
        else d[++num].y=lyd[l],d[num].x=l,d[num].z=r,lyd[l]=r;
    }
    sort(b+1,b+m+1,cmp);
    fo(i,1,b[1].k) a[d[i].x]=d[i].z;
    fo(i,b[1].l,b[1].r) update(i);
    val[b[1].pos]=ans;
    l=b[1].l,r=b[1].r,k=b[1].k;
    fo(i,2,m)
    {
        if(k<b[i].k)
            fo(j,k+1,b[i].k) change(d[j].x,d[j].z);
        else
            fd(j,k,b[i].k+1) change(d[j].x,d[j].y);
        if(l<b[i].l)
            fo(j,l,b[i].l-1) update(j);
        else
            fo(j,b[i].l,l-1) update(j);
        if(r<b[i].r)
            fo(j,r+1,b[i].r) update(j);
        else
            fo(j,b[i].r+1,r) update(j);
        l=b[i].l,r=b[i].r,k=b[i].k;
        val[b[i].pos]=ans;
    }
    fo(i,1,m) printf("%d\n",val[i]);
    return 0;
}

你可能感兴趣的:(分块,莫队算法,曼哈顿距离最小生成树,带修改莫队算法)