BZOJ 2453 维护队列
2017.08.30
2017.08.30
给你一堆数,求$[L,R]$内不同元素的个数。
这道题我直接写的分块+莫队,在莫队排序的基础上加了一层时间作为第一关键字,之后直接暴力莫队就可以了。
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,c[1000010],prx[1000010],pry[1000010],cnt[1000010],ans[1000010],tot,tmp,keeper;
char mode[10];
struct query
{
int x,y,id,blk,pr;
}q[10010];
bool cmp(query tx,query ty)
{
if(tx.pr==ty.pr&&tx.blk==ty.blk) return tx.y<ty.y;
if(tx.pr==ty.pr) return tx.blk<ty.blk;
return tx.pr<ty.pr;
}
void update(int tx,int ty,int l,int r)
{
for(int i=tx+1;i<=ty;++i)
{
if(prx[i]>=l&&prx[i]<=r)
{
cnt[c[prx[i]]]--;
if(!cnt[c[prx[i]]]) tmp--;
if(!cnt[pry[i]]) ++tmp;
cnt[pry[i]]++;
}
c[prx[i]]=pry[i];
}
return;
}
void init()
{
if(q[0].pr!=q[1].pr) update(q[0].pr,q[1].pr,q[0].x,q[0].y);
for(int i=q[1].x;i<=q[1].y;++i)
{
if(!cnt[c[i]]) tmp++;
cnt[c[i]]++;
}
ans[q[1].id]=tmp;
return;
}
void movel(int tx,int ty)
{
if(tx<ty) for(int i=tx;i<ty;++i)
{
cnt[c[i]]--;
if(!cnt[c[i]]) tmp--;
}
else for(int i=tx-1;i>=ty;--i)
{
if(!cnt[c[i]]) tmp++;
cnt[c[i]]++;
}
}
void mover(int tx,int ty)
{
if(tx<ty) for(int i=tx+1;i<=ty;++i)
{
if(!cnt[c[i]]) tmp++;
cnt[c[i]]++;
}
else for(int i=tx;i>ty;--i)
{
cnt[c[i]]--;
if(!cnt[c[i]]) tmp--;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",c+i);
keeper=sqrt(n);
q[0].pr=tmp=1;
for(int i=1;i<=m;++i)
{
scanf("%s",mode);
switch(mode[0])
{
case 'Q':
{
++tot;
scanf("%d%d",&q[tot].x,&q[tot].y);
q[tot].id=tot,q[tot].blk=q[tot].x/keeper+1,q[tot].pr=tmp;
break;
}
case 'R':
{
tmp++;
scanf("%d%d",prx+tmp,pry+tmp);
break;
}
}
}
tmp=0;
sort(q+1,q+tot+1,cmp);
init();
for(int i=2;i<=m;++i)
{
if(q[i-1].pr!=q[i].pr) update(q[i-1].pr,q[i].pr,q[i-1].x,q[i-1].y);
movel(q[i-1].x,q[i].x);
mover(q[i-1].y,q[i].y);
ans[q[i].id]=tmp;
}
for(int i=1;i<=tot;++i) printf("%d\n",ans[i]);
return 0;
}