[国家集训队]数颜色
[国家集训队]数颜色
题解
很水的一道带修莫队板子题。
我们只需要将操作时间看作是当前询问的第三维,排序后跑莫队即可。
三维莫队块长为
n
2
3
n^{\frac{2}{3}}
n32时时间复杂度是最优的,总时间复杂度为
O
(
n
5
6
)
O\left(n^{\frac{5}{6}}\right)
O(n65)。
可以通过块的奇偶来调整排序是从小往大还是从大往小来卡常。
很容易就解决了。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define MAXN 1000005
typedef long long LL;
const LL INF=0x7f7f7f7f;
const LL n1=3000;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while('0'>s||'9'<s){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,m,idx,c[MAXN],tot,d[MAXN];
int cnt[MAXN],ans,answer[MAXN];
struct ming{int p,ito,col;}b[MAXN];
struct ask{int l,r,k,id;}a[MAXN];
bool cmp(ask x,ask y){return x.l/n1==y.l/n1?(x.r/n1==y.r/n1?(x.r/n1&1?x.k<y.k:x.k>y.k):(x.l/n1&1?x.r<y.r:x.r>y.r)):x.l<y.l;}
void insert(int col){ans+=(!cnt[col]);cnt[col]++;}
void remove(int col){cnt[col]--;ans-=(!cnt[col]);}
void updata(int id,int col,int l,int r){if(l<=id&&id<=r)remove(c[id]),insert(col);c[id]=col;}
signed main(){
read(n);read(m);
for(int i=1;i<=n;i++)read(c[i]),d[i]=c[i];
for(int i=1;i<=m;i++){
char opt[5]={};int x,y;scanf("\n%s %d %d",opt,&x,&y);
if(opt[0]=='Q')a[++tot]=(ask){x,y,idx,tot};
else b[++idx]=(ming){x,d[x],y},d[x]=y;
}
sort(a+1,a+tot+1,cmp);int L=1,R=0,K=0;
for(int i=1;i<=tot;i++){
//printf("%d %d %d %d\n",a[i].l,a[i].r,a[i].k,a[i].id);
while(R<a[i].r)insert(c[++R]);
while(L>a[i].l)insert(c[--L]);
while(R>a[i].r)remove(c[R--]);
while(L<a[i].l)remove(c[L++]);
while(K<a[i].k)++K,updata(b[K].p,b[K].col,L,R);
while(K>a[i].k)updata(b[K].p,b[K].ito,L,R),K--;
answer[a[i].id]=ans;
}
for(int i=1;i<=tot;i++)printf("%d\n",answer[i]);
return 0;
}

浙公网安备 33010602011771号