傳說中,莫隊算法能解決一切區間處理問題
這是一個優雅的暴力
那么我們再看一道題
[國家集訓隊]數顏色
膜膜購買了一套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;
}