bzoj2821 作诗(Poetize)分块+二分

预处理的d[i][j]为第i块到第j点的答案

块外的暴力

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
#define maxn 100100
#define maxs 320
int S,T;
int n,m,c;
vector<int> col[maxn];
int a[maxn];
int le[maxs],ri[maxs];
int d[maxs][maxn];
int rec,cas;
int op[maxs],cc[maxn];
int lab[maxn],num;
int ask(int x,int y){
int mid,l=-1,r=col[y].size();
while(l+1!=r){
mid=(l+r)>>1;
if(col[y][mid]>x)r=mid;
else l=mid;
}
return r;
}
inline int sum(int x,int y,int z){
return ask(y,z)-ask(x-1,z);
}
int in[maxn];
inline void put(int x){
if(lab[a[x]]!=cas){
op[++num]=a[x];
lab[a[x]]=cas;
cc[a[x]]=0;
}
cc[a[x]]++;
}
int query(int x,int y){
int ans=0,ss;
int l=in[x]+1;
num=0;
if(in[x]==in[y])for(int i=x;i<=y;i++)put(i);
else for(int i=x;i<=ri[in[x]];i++)put(i);
if(in[x]!=in[y]){
ans=d[l][y];
for(int i=1;i<=num;i++){
ss=sum(le[l],y,op[i]);
if(cc[op[i]]&1){
if(ss&1)ans++;
else if(ss)ans--;
}else{
if(ss&1);
else if(!ss)ans++;
}
}
}else for(int i=1;i<=num;i++)if(!(cc[op[i]]&1))ans++;
return ans;
}
int main(){
scanf("%d%d%d",&n,&c,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
col[a[i]].push_back(i);
}
T=sqrt(n);
if(n-T*T>(T+1)*(T+1)-n)T++;
int now=0;
for(int i=1;i<=n;i++,now--){
if(!now)S++,now=T,le[S]=i,ri[S-1]=i-1;
in[i]=S;
}
ri[S]=n;
for(int i=1;i<=S;i++){
memset(cc,0,sizeof(cc));
rec=0;
for(int j=le[i];j<=n;j++){
if(cc[a[j]]){if(cc[a[j]]&1)rec++;else rec--;}
cc[a[j]]++;
d[i][j]=rec;
}
}
int lans=0;
for(cas=1;cas<=m;cas++){
int x,y;
scanf("%d%d",&x,&y);
x=(x+lans)%n+1;
y=(y+lans)%n+1;
if(x>y)swap(x,y);
lans=query(x,y);
printf("%d\n",lans);
}
}

转载于:https://www.cnblogs.com/wangyucheng/p/3626811.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值