BZOJ 2821: 作诗(Poetize) | 分块
题目:
http://www.lydsy.com/JudgeOnline/problem.php?id=2821
分块.
预处理:
ans[i][j]表示i块到j块的答案;
cnt[i][j]表示i数前j块出现的次数
询问:
ret=l到r包含的整块部分答案,然后暴力处理块外的数出现次数.
我们发现关于每个数x以下情况可以影响到答案
1.x出现奇数次,整块中出现了正偶数次,ret--
2.x出现奇数次,整块中出现了奇数次,ret++
3.x出现偶数次,整块中出现了奇数次,ret++
而x在整块出现次数可以用cnt轻松的求出
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 100005 #define sq 320 using namespace std; int cnt[N][sq],sum[N],n,c,m,S,s,bl[N],br[N],a[N],ans[sq][sq],lastans, vis[N]; void Init() { for (int i=0;i<n;i++) if (i%S==0) br[s]=i-1,bl[++s]=i; br[s]=n-1,bl[s+1]=br[s+1]=n; for (int i=1;i<=s;i++) { for (int j=1;j<=c;j++) cnt[j][i]=cnt[j][i-1]; for (int h=bl[i],t=br[i];h<=t;h++) cnt[a[h]][i]=++sum[a[h]]; } memset(sum,0,sizeof(sum)); for (int i=1;i<=s;i++) { int k=bl[i],tmp=0,t,c; for (int j=k;j<n;j++) sum[a[j]]=0; for (int j=i;j<=s;j++) { t=br[j]; for (;k<=t;k++) { if (vis[a[k]]==i) { c=++sum[a[k]]; if (c%2==0) tmp++; else tmp--; } else vis[a[k]]=i,sum[a[k]]=1; } ans[i][j]=tmp; } } memset(vis,0,sizeof(vis)); } int Query(int l,int r) { if (r-l<2*S) { int tmp=0; for (int i=l;i<=r;i++) if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1; else ++sum[a[i]]; for (int i=l;i<=r;i++) if (vis[a[i]]) tmp+=!(sum[a[i]]%2),vis[a[i]]=0; return tmp; } int L=l/S+1,R=r/S+1; if (l==bl[L]) L--; if (r==br[R]) R++; int st=bl[R],ed=br[L],res=ans[L+1][R-1]; for (int i=l;i<=ed;i++) if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1; else sum[a[i]]++; for (int i=st;i<=r;i++) if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1; else sum[a[i]]++; for (int i=l;i<=ed;i++) if (vis[a[i]]) { int cnt1=sum[a[i]],cnt2=cnt[a[i]][R-1]-cnt[a[i]][L]; if (cnt2>0 && cnt2%2==0 && cnt1%2==1) res--; if (cnt2==0 && cnt1%2==0) res++; if (cnt2%2==1 && cnt1%2==1) res++; sum[a[i]]=vis[a[i]]=0; } for (int i=st;i<=r;i++) if (vis[a[i]]) { int cnt1=sum[a[i]],cnt2=cnt[a[i]][R-1]-cnt[a[i]][L]; if (cnt2>0 && cnt2%2==0 && cnt1%2==1) res--; if (cnt2==0 && cnt1%2==0) res++; if (cnt2%2==1 && cnt1%2==1) res++; sum[a[i]]=vis[a[i]]=0; } return res; } int main() { scanf("%d%d%d",&n,&c,&m);S=sqrt(n); for (int i=0;i<n;i++) scanf("%d",a+i); Init(); for (int i=1,l,r;i<=m;i++) { scanf("%d%d",&l,&r); l=(l+lastans)%n+1; r=(r+lastans)%n+1; if (l>r) swap(l,r); printf("%d\n",lastans=Query(l-1,r-1)); } return 0; }