让菜鸡讲一讲莫队(带修改)

传说中,莫队算法能解决一切区间处理问题

这是一个优雅的暴力

那么我们再看一道题


[国家集训队]数颜色

膜膜购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答膜膜的提问。膜膜会像你发布如下指令:

1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。

2、 R P Col 把第P支画笔替换为颜色Col。

为了满足膜膜的要求,你知道你需要干什么了吗?


我™当然知道要干什么了

这个比上次那个题多了修改操作!普通莫队已经派不上用场了!

然而普通莫队和带修改莫队没什么区别

当时提莫莫涛大佬发明了莫队之后,

因为有不能修改的debuff,

引起了后人的不爽,

于是后人就发明了带修改莫队

具体来说,带修改莫队与普通莫队有这个不同:

除了l,r两个指针之外,还增加了指针t

这个指针的含义是当前序列是在第t次修改后的状态

同时每个询问也要多记一个东西,就是这个是在第几次修改发生后询问的。

那么询问的排序方法需要改变:

inline const int operator < (const trouble &b)const
    {if(cua==b.cua)return r==b.r?t<b.t:r<b.r;return cua<b.cua;}
"即先比较l的块,再比较r,再比较时间"

还要在原来的add,del的基础上多写一个函数,我把它叫做时光机(雾

void tmc(int now,int a)
{
    if(q[a].l<=ch[now].d && ch[now].d<=q[a].r)
    {
        if(--cnt[v[ch[now].d]]==0)num--;
        if(cnt[ch[now].to]++==0)num++;
    }
    swap(v[ch[now].d],ch[now].to);
}

它的作用是把序列的状态变成第now次之后,

同时修改计数君cnt和答案num。

    if(q[a].l<=ch[now].d && ch[now].d<=q[a].r)

现在这次修改的地方是ch[now].d,那么只有它在l与r之间的时候才会对cnt产生影响

        if(--cnt[v[ch[now].d]]==0)num--;
        if(cnt[ch[now].to]++==0)num++;

修改cnt和num

    swap(v[ch[now].d],ch[now].to);

把当前颜色和目标颜色交换

为什么是交换?

假设这是t现在的状态

   t
1234567... <timeline>

如果现在要把时间变成第5次修改之后,

    t
1234567... <timeline>

t到达了5,执行一次tmc(5,...),会把修改的那里交换一次;

如果现在又要把时间返回到第4次修改之后,

   t
1234567... <timeline>

t离开了5,执行一次tmc(5,...),会把修改的那里交换回来


那么这里是[国家集训队]数颜色的代码,

这也可以作为带修改莫队的模板了。

#include<bits/stdc++.h>
using namespace std;
inline int gotcha()
{
    register int a=0,b=1,c=getchar();
    while(!isdigit(c))b^=c=='-',c=getchar();
    while(isdigit(c))a=(a<<3)+(a<<1)+c-48,c=getchar();
    return b?a:-a;
}
const int _ = 10002 , __ = 1000002 , teemo = 133;
struct trouble
{
    int l,r,cua,num,t;
    inline const int operator < (const trouble &b)const
    {if(cua==b.cua)return r==b.r?t<b.t:r<b.r;return cua<b.cua;}
}q[_];
struct changes{int d,to;}ch[_];
int n,m,v[_],cnt[__]={0},num=0,ans[_],qc=0,cc=0;
void add(int d){if(cnt[d]++==0)num++;}void del(int d){if(--cnt[d]==0)num--;}
void tmc(int now,int a)
{
    if(q[a].l<=ch[now].d && ch[now].d<=q[a].r)
    {if(--cnt[v[ch[now].d]]==0)num--;if(cnt[ch[now].to]++==0)num++;}
    swap(v[ch[now].d],ch[now].to);
}
int main()
{
    register int i,j,k,l,r,t;
    register char op[3];
    n=gotcha(),m=gotcha();
    for(i=1;i<=n;i++)v[i]=gotcha();
    for(i=1;i<=m;i++)
    {
        scanf("%s",op),j=gotcha(),k=gotcha();
        if(op[0]=='Q')q[++qc].l=j,q[qc].r=k,q[qc].cua=q[qc].l/teemo,q[qc].num=qc,q[qc].t=cc;
        else ch[++cc].d=j,ch[cc].to=k;
    }
    sort(q+1,q+qc+1);
    l=1,r=0,t=0;
    for(i=1;i<=qc;i++)
    {
        while(l<q[i].l)del(v[l++]);while(l>q[i].l)add(v[--l]);
        while(r<q[i].r)add(v[++r]);while(r>q[i].r)del(v[r--]);
        while(t<q[i].t)tmc(++t,i);while(t>q[i].t)tmc(t--,i);
        ans[q[i].num]=num;
    }
    for(i=1;i<=qc;i++)printf("%d\n",ans[i]);
    return 0;
}
posted @ 2018-02-03 15:50  iot;  阅读(210)  评论(9编辑  收藏  举报
知识共享许可协议
年轻人,你需要更多的知识