bzoj 2821: 作诗(Poetize)【分块】
参考:http://hzwer.com/3663.html
除了麻烦一点也没什么难的,就是要注意细节。
首先\( O(n\sqrt{n}) \)时间下预处理出\( f[i][j] \),表示第\( i \)块和第\( j \)块之间的答案。\( L \)表示这个块的左端点,\( R \)表示这个块的右端点,\( v\)标记计算过程中已经被算到答案里的数字,\( bl \)表示这个节点属于第几个块,\( fr \)表示当前这个值最早出现的位置,\( la \)表示当前这个值最晚出现的位置。
询问的时候,当\( (l,r) \)处于同一个或者相邻两个快里,则直接暴力统计。否则把其完全跨越的块用\( f \) 查询,得到中间大块\( x-y \)的答案,考虑\( l-x \)和\( y-r \)对答案的影响,对于每个数统计它在\( x-y \)出现次数\( t1 \),以及\( l-r \)出现次数\( t2 \),根据\( t1 \),\( t2 \)的奇偶性考虑其对答案的影响。
对于清理数组要用\( for \),否则无法保证复杂度。
时间复杂度:\( O(n\sqrt{n}log_2n) \)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100005,K=1505,inf=1e9;
int n,m,c,kuai,cnt,bl[N],L[N],R[N],tmp[N],f[K][K],fr[N],la[N],las,a[N];
bool v[N];
struct qwe
{
int p,v;
}b[N];
bool cmp(const qwe &a,const qwe &b)
{
return (a.v<b.v)||(a.v==b.v&&a.p<b.p);
}
int read()
{
int r=0,f=1;
char p=getchar();
while(p<'0'||p>'9')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
int up(int x,int v)
{
int l=fr[v],r=la[v],re=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(x<b[mid].p)
r=mid-1;
else
l=mid+1,re=mid;
}
return re;
}
int down(int x,int v)
{
int l=fr[v],r=la[v],re=inf;
while(l<=r)
{
int mid=(l+r)>>1;
if(x>b[mid].p)
l=mid+1;
else
re=mid,r=mid-1;
}
return re;
}
int zhao(int x,int y,int v)
{
return max(up(y,v)-down(x,v)+1,0);
}
int ques(int x,int y)
{
int ans=0,t1,t2,a1,bx=bl[x],by=bl[y];
if(bx==by||bx+1==by)
{
for(int i=x;i<=y;i++)
if(!v[a[i]])
{
int t=zhao(x,y,a[i]);
if(!(t&1))
{
v[a[i]]=1;
ans++;
}
}
for(int i=x;i<=y;i++)
v[a[i]]=0;
}
else
{
int l=L[bx+1],r=R[by-1];
ans=f[bx+1][by-1];
for(int i=x;i<l;i++)
if(!v[a[i]])
{
t1=zhao(x,y,a[i]),t2=zhao(l,r,a[i]);
if(!(t1&1))
{
if((t2&1)||!t2)
ans++;
}
else if(!(t2&1)&&t2)
ans--;
v[a[i]]=1;
}
for(int i=r+1;i<=y;i++)
if(!v[a[i]])
{
t1=zhao(x,y,a[i]),t2=zhao(l,r,a[i]);
if(!(t1&1))
{
if((t2&1)||!t2)
ans++;
}
else if(!(t2&1)&&t2)
ans--;
v[a[i]]=1;
}
for(int i=x;i<l;i++)
v[a[i]]=0;
for(int i=r+1;i<=y;i++)
v[a[i]]=0;
}
return ans;
}
int main()
{
n=read(),c=read(),m=read();//cout<<n<<m<<c;
for(int i=1;i<=n;i++)
a[i]=read();
kuai=sqrt((double)n/log((double)n)*log(2));
if(n%kuai)
cnt=n/kuai+1;
else
cnt=n/kuai;
for(int i=1;i<=n;i++)
bl[i]=(i-1)/kuai+1;
for(int i=1;i<=cnt;i++)
L[i]=(i-1)*kuai+1,R[i]=i*kuai;
R[cnt]=n;
int tot;
for(int i=1;i<=cnt;i++)
{
for(int j=L[i];j<=n;j++)
tmp[a[j]]=0;
tot=0;
for(int j=L[i];j<=n;j++)
{
if(!(tmp[a[j]]&1)&&tmp[a[j]])//注意当a[j]的个数为0的时候就不用减了
tot--;
tmp[a[j]]++;
if(!(tmp[a[j]]&1))
tot++;
f[i][bl[j]]=tot;
}
}
for(int i=1;i<=n;i++)
b[i].p=i,b[i].v=a[i];
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++)
{
if(!fr[b[i].v])
fr[b[i].v]=i;
la[b[i].v]=i;
}
while(m--)
{
int l=read(),r=read(),x=(l+las)%n+1,y=(r+las)%n+1;
if(x>y)
swap(x,y);
las=ques(x,y);
printf("%d\n",las);
}
return 0;
}