题目

https://www.luogu.org/problem/P3939

 

 

题解

一开始以为是求一个区间内的颜色种类数,还带修改,当场吓懵。。。

结果是求一个区间内某种颜色的个数。。。

这不裸的分块吗?

一看数据范围n<=300000

咦,莫非有更快的算法

好像是有的

对于每种颜色都开一个set,存每种颜色的坐标在哪里,然后lower_bound查一下,就可以啦

然而set无法查一个点的排名

于是就用了n个vector,按坐标依次压进对应颜色的vector

然后就可以lower_bound查排名了

由于是交换两个相邻的数,所以vector里面的相对顺序是不变的

存一下每个点的pos,所以就可以完成修改操作了

代码:(挺好写的)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 300005
vector<int> b[N];
vector<int>::iterator t1,t2;
int a[N],pos[N],siz[N];
int main()
{
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	int n,m,i,l,r,c,x,op;
	n=gi();m=gi();
	for(i=1;i<=n;i++){
		a[i]=gi();
		b[a[i]].push_back(i);
		pos[i]=siz[a[i]];
		siz[a[i]]++;
	}
	for(i=1;i<=m;i++){
		op=gi();
		if(op==1){
			l=gi();r=gi();c=gi();
			if(siz[c]){
				t1=lower_bound(b[c].begin(),b[c].end(),l);
				t2=upper_bound(b[c].begin(),b[c].end(),r);
				t2--;
				printf("%d\n",t2-t1+1);
			}
			else
				printf("0\n");
		}
		if(op==2){
			x=gi();
			if(a[x]!=a[x+1]){
				b[a[x]][pos[x]]++;
				b[a[x+1]][pos[x+1]]--;
				swap(a[x],a[x+1]);
				swap(pos[x],pos[x+1]);
			}
		}
	}
}