[国家集训队]数颜色

[国家集训队]数颜色

题解

很水的一道带修莫队板子题。

我们只需要将操作时间看作是当前询问的第三维,排序后跑莫队即可。
三维莫队块长为 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;
}

谢谢!!!

posted @ 2021-01-02 11:46  StaroForgin  阅读(7)  评论(0)    收藏  举报  来源