【bzoj2821】作诗(Poetize)
分块做法*
ps:第一篇博客,有点小激动,有错误大佬别怼我;
题目大概是这样的;
类似于区间众数,在询问的区间中统计出现过偶数次的元素和。
那么这种类型的题目分块比暴力优越在哪??是的,只是因为预处理而已;
先用f[i][j]统计出:第i块 到 第j块中询问的答案;
对于不完整的块,我们最多做不超过块大小两倍,时间上有保证;
查询*
对于区间[a,b],可分为三个部分:1.[a,min(b,bl[a]*blo], 2.[bl[a]*blo+1,(bl[b-1]*blo], 3.[bl[b-1]*blo+1,b];
注意到第二部分的答案是已知的,那么影响结果的只能是1,3部分的元素;
每个暴力查询他在大区间中出现的次数,判断他在完整的块里是否被统计过,修改rtn;
应该就这些,另外对于查询他出现的次数,二分就行了,用vector记录这个元素所有出现的位置,看哪些在[a,b]中;
好了,代码如xia:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#include <map>
#define LL long long
using namespace std;
int read(){
int rtn=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0')rtn=rtn*10+ch-'0',ch=getchar();
return rtn*f;
}
int n,q,c,id,lastans,m,v[100010],blo,flag[100010],cnt[100010],bl[100010],f[1505][1505];
vector<int>ve[100010];//不用vector写法复杂一些,蒟蒻不会;
//如果按照sqrt(n/log(n)*log(2))分,块的数量比原来增多,;
void reset(int x){
int l=(x-1)*blo+1,tot=0;
for(int i=l;i<=n;i++)cnt[v[i]]=0;
for(int i=l;i<=n;i++){
int t=bl[i];
cnt[v[i]]++;
if(cnt[v[i]]==1){
f[x][t]=tot;
continue;
}
if(!(cnt[v[i]]&1))tot++;
if(cnt[v[i]]&1)tot--;
f[x][t]=tot;
//预处理,偶数加一,奇数减一,等于一的时候特判;
}
}
int Query(int l,int r,int x){
return (upper_bound(ve[x].begin(),ve[x].end(),r)-
lower_bound(ve[x].begin(),ve[x].end(),l));
}
int query(int a,int b){
int ans=0,l=bl[a]*blo+1,r=(bl[b]-1)*blo;
if(bl[a]==bl[b]||bl[a]+1==bl[b]){
for(int i=a;i<=b;i++){
if(flag[v[i]])continue;
int t1=Query(a,b,v[i]);
if(!(t1&1)){flag[v[i]]=1;ans++;}
}
for(int i=a;i<=b;i++)flag[v[i]]=0;
}
else{
ans=f[bl[a]+1][bl[b]-1];
for(int i=a;i<=bl[a]*blo;i++){
if(flag[v[i]])continue;
int t1=Query(a,b,v[i]);
int t2=Query(l,r,v[i]);
if(!(t1&1))
if(t2&1||!t2)ans++;
if(t1&1)
if(!(t2&1)&&t2)ans--;
flag[v[i]]=1;
}
for(int i=(bl[b]-1)*blo+1;i<=b;i++){
if(flag[v[i]])continue;
int t1=Query(a,b,v[i]);
int t2=Query(l,r,v[i]);
if(!(t1&1))
if(t2&1||!t2)ans++;
if(t1&1)
if(!(t2&1)&&t2)ans--;
flag[v[i]]=1;
}
for(int i=a;i<=bl[a]*blo;i++)flag[v[i]]=0;
for(int i=(bl[b]-1)*blo+1;i<=b;i++)flag[v[i]]=0;
}
return ans;
}
int main()
{
n=read(),c=read(),q=read();
blo=sqrt((double)n/log((double)n)*log(2));//注意块大小
for(int i=1;i<=n;i++){
v[i]=read();
bl[i]=(i-1)/blo+1;
ve[v[i]].push_back(i);
}
if(n%blo)m=n/blo+1;
else m=n/blo;
for(int i=1;i<=m;i++)reset(i);
for(int i=1;i<=q;i++){
int x=read(),y=read();
x=(x+lastans)%n+1,y=(y+lastans)%n+1;
if(x>y)swap(x,y);
lastans=query(x,y);
printf("%d\n",lastans);
}
return 0;
}