P1903 [国家集训队]数颜色 / 维护队列
带修莫队,在原来的基础上加一个时间指针 $t$
每次移动时除了 $l,r$ 移动 $t$ 也跟着移动,并更新状态
为了维护时间变化
所以维护一个 $pos[i]$ 表示第 $i$ 次修改的位置,$co[i]$ 表示第 $i$ 次修改的颜色
$pre[i]$ 表示第 $i$ 次修改前 $pos[i]$ 的颜色
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e5+7,M=1e6+7; int n,m,Div; int cnt[M],col[N],ans[N];//col维护当前序列状态 int pos[N],pre[N],co[N]; struct dat{ int l,r,t,bel; inline bool operator < (const dat &tmp) const { if(l/Div!=tmp.l/Div) return l/Div<tmp.l/Div; return r/Div!=tmp.r/Div ? r/Div<tmp.r/Div : t/Div<tmp.t/Div; } }q[N]; int main() { n=read(),m=read(); for(int i=1;i<=n;i++) col[i]=read(); int ta=0,tb=0,a,b; char s[7]; for(int i=1;i<=m;i++) { scanf("%s",s); a=read(),b=read(); if(s[0]=='Q') q[++ta]=(dat){a,b,tb,ta}; else { tb++; pos[tb]=a; co[tb]=b; pre[tb]=col[a]; col[a]=b; } } for(int i=tb;i;i--) col[pos[i]]=pre[i];//把序列的修改撤销回来 Div=ceil( exp( (log(n)+log(tb))/3 ) );//奇怪的块大小 sort(q+1,q+ta+1); int l=1,r=0,t=0,tot=0; for(int i=1;i<=ta;i++) { while(q[i].l<l) tot+=!cnt[col[--l]]++; while(q[i].l>l) tot-=!--cnt[col[l++]]; while(q[i].r<r) tot-=!--cnt[col[r--]]; while(q[i].r>r) tot+=!cnt[col[++r]]++; while(q[i].t<t)//移动时间指针 { if(pos[t]>=l&&pos[t]<=r) tot-=!--cnt[col[ pos[t] ]]; col[pos[t]]=pre[t]; if(pos[t]>=l&&pos[t]<=r) tot+=!cnt[col[ pos[t] ]]++; t--; } while(q[i].t>t)//移动时间指针 { t++; if(pos[t]>=l&&pos[t]<=r) tot-=!--cnt[col[ pos[t] ]]; col[pos[t]]=co[t]; if(pos[t]>=l&&pos[t]<=r) tot+=!cnt[col[ pos[t] ]]++; } ans[q[i].bel]=tot; } for(int i=1;i<=ta;i++) printf("%d\n",ans[i]); return 0; }