讓菜雞講一講莫隊(帶修改)


傳說中,莫隊算法能解決一切區間處理問題

這是一個優雅的暴力

那么我們再看一道題


[國家集訓隊]數顏色

膜膜購買了一套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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM