版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目
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]);
}
}
}
}