https://www.luogu.com.cn/problem/P1903
离线修改的莫队可以多增加一维的时间,然后变成[l,r,t]->[l+-1,r+-1,t+-1]
先按左端点块排序,再按右端点块排序,再按时间大小排序。
块的大小需要是n^(2/3),可以吧总复杂度变成O(n^(5/3)),优于n^2
实际上在1e5的数据下洛谷最大的点只跑了846ms,还没加读入优化
#include<bits/stdc++.h>
using namespace std;
const int maxl=1e6+10;
int n,m,len,tot,cntq,cntc;
int a[maxl],b[maxl],tmp[maxl],cnt[maxl];
int bel[maxl],ans[maxl];
struct qry
{
int l,r,t,id;
}q[maxl];
struct mdf
{
int pos,col;
}c[maxl];
char s[2];
inline bool cmp(const qry &a,const qry &b)
{
if(bel[a.l]==bel[b.l])
{
if(bel[a.r]==bel[b.r])
return a.t<b.t;
return bel[a.r]<bel[b.r];
}
return bel[a.l]<bel[b.l];
}
inline void prework()
{
scanf("%d%d",&n,&m);
len=pow(n,2.0/3.0);tot=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
bel[i]=(i-1)/len+1;
}
int x,y;cntq=0;cntc=0;
for(int i=1;i<=m;i++)
{
scanf("%s",s);
scanf("%d%d",&x,&y);
if(s[0]=='Q')
q[++cntq]=qry{x,y,cntc,cntq};
else
c[++cntc]=mdf{x,y};
}
sort(q+1,q+1+cntq,cmp);
}
inline void mainwork()
{
int l=1,r=0,clk=0,now=0;
for(int i=1;i<=cntq;i++)
{
while(r<q[i].r)
now+=!cnt[a[++r]]++;
while(l>q[i].l)
now+=!cnt[a[--l]]++;
while(r>q[i].r)
now-=!--cnt[a[r--]];
while(l<q[i].l)
now-=!--cnt[a[l++]];
while(clk<q[i].t)
{
++clk;
if(q[i].l<=c[clk].pos && c[clk].pos<=q[i].r)
{
now-=!--cnt[a[c[clk].pos]];
now+=!cnt[c[clk].col]++;
}
swap(a[c[clk].pos],c[clk].col);
}
while(clk>q[i].t)
{
if(q[i].l<=c[clk].pos && c[clk].pos<=q[i].r)
{
now-=!--cnt[a[c[clk].pos]];
now+=!cnt[c[clk].col]++;
}
swap(a[c[clk].pos],c[clk].col);
--clk;
}
ans[q[i].id]=now;
}
}
inline void print()
{
for(int i=1;i<=cntq;i++)
printf("%d\n",ans[i]);
}
int main()
{
prework();
mainwork();
print();
return 0;
}