题目:
题目链接:[LOUGU 作诗]
题解:
题目就是让求区间的正偶次个数,这里可以仿照区间众数的做法,整体下来进行分块就比较复杂,还需要考虑衔接块和大整块,但是还是比较好思考的。
(重点看注释)
代码:
// luogu-judger-enable-o2
//有是不挺的TLE,,又是要卡常,,,开O2过的
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int sea=1e5+7;
int n,m,mx,ans,top,num,block,belong[sea],cnt[400][sea],f[400][400],l[sea],a[sea],c[sea],st[sea];
int main()
{
n=read(); mx=read(); m=read(); ans=0; block=sqrt(n);
for(int i=1;i<=n;i++)
{
a[i]=read(),belong[i]=(i-1)/block+1;
if(belong[i]!=belong[i-1]) l[belong[i]]=i;
}
belong[n+1]=belong[n]+1; l[belong[n+1]]=n+1;//建块,跟之前的建块有点不同,这里主要是要每个块的左端点
for(int i=1;i<=belong[n];i++)
{
int t=0;
for(int j=l[i];j<=n;j++)
{
cnt[i][a[j]]++;
if((cnt[i][a[j]]>1)&&(cnt[i][a[j]]&1)) t--;
else if(!(cnt[i][a[j]]&1)) t++;
if(belong[j]!=belong[j+1]) f[i][belong[j]]=t;
//这里用t来处理答案,本人觉得写得比较巧妙。
}
}
//记录每个块从l开始到n时的众数出现的正偶次存在cnt[][]中 ,f[][]是记录每一块的初始答案
while(m--)
{
int x=read(), y=read();
x=(x+ans)%n+1,y=(y+ans)%n+1; ans=0;
if(x>y) swap(x,y);
//处理读入(在线做)
if(belong[x]==belong[y])
{
for(int i=x;i<=y;i++) c[a[i]]++, st[++top]=a[i];
while(top)
{
if(c[st[top]])
ans+=(c[st[top]]&1)^1,c[st[top]]=0;
top--;
}
//栈处理小区间的答案
printf("%d\n",ans); continue;
}
if(belong[y]-belong[x]>=2) ans=f[belong[x]+1][belong[y]-1];//中间有整块
for(int i=x;i<l[belong[x]+1];i++) c[a[i]]++,st[++top]=a[i];
for(int i=l[belong[y]];i<=y;i++) c[a[i]]++,st[++top]=a[i];
//衔接块
while(top)
{
if(c[st[top]])
{
int t=st[top],ins=cnt[belong[x]+1][t]-cnt[belong[y]][t];//这里就是对于衔接点的处理,
if(ins>0&&(!(ins&1))&&(c[t]&1)) ans--;
else if(ins>0&&(ins&1)&&(c[t]&1)) ans++;
else if(!ins&&(!(c[t]&1))) ans++;
c[t]=0;
}
top--;
}
printf("%d\n",ans);
}
return 0;
}