当前位置: 代码迷 >> 综合 >> 【分块】[LOUGU 作诗] 正偶次分块
  详细解决方案

【分块】[LOUGU 作诗] 正偶次分块

热度:45   发布时间:2024-01-17 00:01:32.0

题目:

题目链接:[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;
} 

Continue……