题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=2120
思路
这道题可以用分块,可以用莫队,可以用数结……
然而我只会分块和莫队耶
分块
首先来讲一下分块的思路:
每个点记录一个代表这个颜色上一次出现的地点,显然中的就是第一次出现的颜色。
将数列分块,每一块块内排序,这样查询时只需二分寻找的点。
BZOJ交不过耶,是不是我常数太大了qwq
分块代码
#pragma GCC optimize(2)
//然而强制开O2也救不了我的大常数
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
const int maxn=10000;
const int maxc=1000000;
int belong[maxn+10],n,m,color[maxn+10],size;
int pre[maxn+10],nowc[maxc+10],r[maxn+10];
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int main()
{
n=read();
m=read();
size=(int)sqrt(n);
for(register int i=1; i<=n; ++i)
{
color[i]=read();
belong[i]=(i-1)/size+1;
}
for(register int i=1; i<=n; ++i)
{
r[i]=pre[i]=nowc[color[i]];
nowc[color[i]]=i;
}
int k=n/size;
for(register int i=1; i<=k; ++i)
{
std::sort(r+(i-1)*size+1,r+i*size+1);
}
if(n%size!=0)
{
std::sort(r+(n-n%size)+1,r+n+1);
}
while(m--)
{
char ch=getchar();
while((ch!='Q')&&(ch!='R'))
{
ch=getchar();
}
int a,b;
scanf("%d%d",&a,&b);
if(ch=='Q')
{
int ans=0;
if(belong[a]==belong[b])
{
for(register int i=a; i<=b; ++i)
{
if(pre[i]<a)
{
++ans;
}
}
printf("%d\n",ans);
}
else
{
int be=belong[a]*size;
if(be>n)
{
be=n;
}
for(register int i=a; i<=be; ++i)
{
if(pre[i]<a)
{
++ans;
}
}
be=(belong[b]-1)*size+1;
for(register int i=be; i<=b; ++i)
{
if(pre[i]<a)
{
++ans;
}
}
for(register int i=belong[a]+1; i<belong[b]; ++i)
{
ans+=std::lower_bound(r+(i-1)*size+1,r+i*size+1,a)-(r+(i-1)*size+1);
}
printf("%d\n",ans);
}
}
else
{
color[a]=b;
memset(nowc,0,sizeof nowc);
for(register int i=1; i<=n; ++i)
{
r[i]=pre[i]=nowc[color[i]];
nowc[color[i]]=i;
}
for(register int i=1; i<=k; ++i)
{
std::sort(r+(i-1)*size+1,r+i*size+1);
}
if(n%size!=0)
{
std::sort(r+n-n%size+1,r+n+1);
}
}
}
return 0;
}
莫队
这不就是裸的带修改莫队吗?(而且时间复杂度和常数似乎都优越一些耶)
莫队代码
#include <cstdio>
#include <cmath>
#include <algorithm>
const int maxn=10000;
const int maxc=1000000;
struct query
{
int l,r,t,id;
};
int belong[maxn+10],n,m,color[maxn+10];
int nowl,nowr,nowt,ans[maxn+10],cntq,cntm,used[maxc+10],nowans;
int pos[maxn+10],prec[maxn+10],nowc[maxn+10];
query q[maxn+10];
bool cmp(const query &a,const query &b)
{
if(belong[a.l]==belong[b.l])
{
if(belong[a.r]==belong[b.r])
{
return a.t<b.t;
}
return belong[a.r]<belong[b.r];
}
return belong[a.l]<belong[b.l];
}
inline int modify(int po,int op)
{
int pr=used[color[po]];
used[color[po]]+=op;
if(pr==0)
{
++nowans;
}
else if(used[color[po]]==0)
{
--nowans;
}
return 0;
}
inline int change_time(int po,int c)
{
if((nowl<=po)&&(po<=nowr))
{
--used[color[po]];
if(used[color[po]]==0)
{
--nowans;
}
color[po]=c;
if(used[color[po]]==0)
{
++nowans;
}
++used[color[po]];
}
else
{
color[po]=c;
}
return 0;
}
inline int solve(int x)
{
while(nowt<q[x].t)
{
++nowt;
change_time(pos[nowt],nowc[nowt]);
}
while(nowt>q[x].t)
{
change_time(pos[nowt],prec[nowt]);
--nowt;
}
while(nowl<q[x].l)
{
modify(nowl++,-1);
}
while(nowl>q[x].l)
{
modify(--nowl,1);
}
while(nowr<q[x].r)
{
modify(++nowr,1);
}
while(nowr>q[x].r)
{
modify(nowr--,-1);
}
ans[q[x].id]=nowans;
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; ++i)
{
scanf("%d",&color[i]);
}
for(register int i=1; i<=m; ++i)
{
char ch[10];
int a,b;
scanf("%s%d%d",ch,&a,&b);
if(ch[0]=='Q')
{
q[++cntq].l=a;
q[cntq].r=b;
q[cntq].t=cntm;
q[cntq].id=cntq;
}
else
{
pos[++cntm]=a;
prec[cntm]=color[a];
nowc[cntm]=b;
color[a]=b;
}
}
int size=(int)sqrt(cntq);
for(register int i=1; i<=n; ++i)
{
belong[i]=(i-1)/size+1;
}
std::sort(q+1,q+cntq+1,cmp);
nowl=nowr=nowans=used[color[1]]=1;
nowt=cntm;
for(register int i=1; i<=cntq; ++i)
{
solve(i);
}
for(register int i=1; i<=cntq; ++i)
{
printf("%d\n",ans[i]);
}
return 0;
}