题解 P3939 【数颜色】
「QQ红包」
2017-11-01 23:27:52
肯定有人学数据结构学傻了。直接用 vector记录每个颜色出现的位置,然后二分一下就好。
因为颜色的范围很小,都不用离散。
```cpp
#include<bits/stdc++.h>
using namespace std;
int read()
{
char s;
int k=0,base=1;
while((s=getchar())!='-'&&s!=EOF&&!(s>='0'&&s<='9'));
if(s==EOF)exit(0);
if(s=='-')base=-1,s=getchar();
while(s>='0'&&s<='9')
{
k=k*10+(s-'0');
s=getchar();
}
return k*base;
}
void write(int x)
{
if(x<0)
{
putchar('-');
write(-x);
}
else
{
if(x/10)write(x/10);
putchar(x%10+'0');
}
}
const int maxn=3e5+100;
const int maxm=6e5+100;
int n,m,bj,X,Y,Z,p1,p2;
int a[maxn],ans;
int tong[maxn];
int t1[maxn],Max;
int t[11][maxn*2];
vector<int> g[maxn];
bool f1,f2,f3,f4;
void xg(int i,int x,int d)//t[i][x]+=d;
{
int s=x;
while (s<=n)
{
t[i][s]+=d;
s+=(s&(-s));
}
return;
}
int qh(int i,int x)
{
int s=x,sum=0;
while (s)
{
sum+=t[i][s];
s-=(s&(-s));
}
return sum;
}
int main()
{
n=read();m=read();
f4=true;
for (int i=1;i<=n;i++)
{
a[i]=read();
Max=max(a[i],Max);
if (tong[a[i]]!=0) f4=false;
if (f4) tong[a[i]]=i;
t1[a[i]]++;//cnt
}
if (Max<=10) f2=true; else f2=false;
/* if (n<=1000)//一千以内的
{
while (m--)
{
bj=read();
if (bj==1)
{
ans=0;
X=read();Y=read();Z=read();
for (int i=X;i<=Y;i++)
if (a[i]==Z) ans++;
printf("%d\n",ans);
} else
{
X=read();
swap(a[X],a[X+1]);
}
}
return 0;
}
if (f4)//每个颜色只出现了一次
{
while (m--)
{
bj=read();
if (bj==1)
{
X=read();Y=read();Z=read();
if (X<=tong[Z]&&tong[Z]<=Y) printf("1\n"); else printf("0\n");
} else
{
X=read();
//a[X],a[X+1];
tong[a[X]]++;
tong[a[X+1]]--;
swap(a[X],a[X+1]);
}
}
return 0;
}
if (f2)//颜色小于10种,顺便说一下,不要用什么树状数组,前缀和维护一下就好
{
for (int i=1;i<=n;i++) xg(a[i],i,1);
while (m--)
{
bj=read();
if (bj==1)
{
X=read();Y=read();Z=read();
ans=qh(Z,Y)-qh(Z,X-1);
printf("%d\n",ans);
} else
{
X=read();
xg(a[X],X,-1);
xg(a[X],X+1,1);
xg(a[X+1],X+1,-1);
xg(a[X+1],X,1);
swap(a[X+1],a[X]);
}
}
return 0;
}*/
//然后还有一个部分分:特殊性质1
//这个如果r-l<=20,暴力这一部分,否则暴力l~l-1和r+1~n,然后用整个的出现次数减一下就好
for (int i=1;i<=n;i++) g[a[i]].push_back(i);
while (m--)
{
bj=read();
if (bj==1)
{
X=read();Y=read();Z=read();
p1=lower_bound(g[Z].begin(),g[Z].end(),X)-g[Z].begin();//找第一个>=X的
p2=upper_bound(g[Z].begin(),g[Z].end(),Y)-g[Z].begin()-1;//找第一个<=Y的
if (p2<p1) printf("0\n"); //这个注意要判掉
else
printf("%d\n",p2-p1+1);
} else
{
X=read();
if (a[X]==a[X+1]) continue;//修改,如果颜色相同不用改了
p1=lower_bound(g[a[X]].begin(),g[a[X]].end(),X)-g[a[X]].begin();
g[a[X]][p1]++;
p2=lower_bound(g[a[X+1]].begin(),g[a[X+1]].end(),X+1)-g[a[X+1]].begin();
g[a[X+1]][p2]--;
swap(a[X],a[X+1]);//记得换掉
}
}
return 0;
}
```