解题:luogu p1903 数颜色 / 维护队列
题面
前排提醒:这篇题解不太是(啥玩意=。=???)正解,只能在O2优化后通过(O2后最快的话最慢的一个点跑了300+ms,不O2直接TLE(或许有什么手写bitset这种东西可以过=。=?))
初学分块的蒟蒻用暴力的分块卡过去了想写篇题解,dalao们轻喷=。=
直接分块+bitset,离散化后记录每块内每种颜色出现的次数,这样一次修改是
为了提高效率,这里可以适当加大块的大小,这样块合并会变少而零散区间的统计会变多,在这个题效率会更高一点(我一开始弄了一个
// luogu-judger-enable-o2
#include<cmath>
#include<cstdio>
#include<cctype>
#include<bitset>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=50005,M=100005,Sq=20;
struct a
{
int typ;
int ll,rr;
}q[N];
int n,m,t1,t2,t3,t4,sqr,cnt,xnt,len;
int pts[Sq][2],app[Sq][M];
int a[N],blo[N],uni[2*N];
bitset<M> sta[Sq],qry;
char rd[5];
inline int read()
{
int ret=0;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
while(isdigit(ch))
ret=(ret<<1)+(ret<<3)+(ch^48),ch=getchar();
return ret;
}
inline void write(int x)
{
if(x>9) write(x/10);
putchar(x%10+48);
}
int main()
{
register int i,j;
n=read(),m=read(),xnt=n;
sqr=pow(n,0.75),pts[cnt=1][0]=1;
for(i=1;i<=n;i++)
{
a[i]=read(),uni[i]=a[i];
blo[i]=(i-1)/sqr+1;
if(i%sqr==0)
{
pts[cnt++][1]=i;
pts[cnt][0]=i+1;
}
}
pts[cnt][1]=n;
for(i=1;i<=m;i++)
{
scanf("%s",rd),t1=read(),t2=read();
q[i].ll=t1,q[i].rr=t2,q[i].typ=(rd[0]=='R');
if(q[i].typ) uni[++xnt]=t2;
}
sort(uni+1,uni+1+xnt),len=unique(uni+1,uni+1+xnt)-uni-1;
for(i=1;i<=n;i++)
{
a[i]=lower_bound(uni+1,uni+1+len,a[i])-uni;
if(++app[blo[i]][a[i]]==1) sta[blo[i]][a[i]]=true;
}
for(i=1;i<=m;i++)
{
t1=q[i].ll,t2=q[i].rr;
if(q[i].typ)
{
int bel=blo[t1],newc=lower_bound(uni+1,uni+1+len,t2)-uni;
if(!(--app[bel][a[t1]])) sta[bel][a[t1]]=false;
if(++app[bel][newc]==1) sta[bel][newc]=true; a[t1]=newc;
}
else
{
qry.reset(),t3=blo[t1],t4=blo[t2];
if(t3!=t4)
{
for(j=t1;j<=pts[t3][1];j++) qry[a[j]]=true;
for(j=pts[t4][0];j<=t2;j++) qry[a[j]]=true;
for(j=t3+1;j<=t4-1;j++) qry|=sta[j];
}
else for(j=t1;j<=t2;j++) qry[a[j]]=true;
write((int)qry.count()),puts("");
}
}
return 0;
}