您的位置:首页 > 其它

bzoj 2821: 作诗(Poetize) 分块

2016-11-17 08:17 381 查看

题意

给出n个数,每次询问一个区间内出现正偶数次的数的种类数。强制在线。

n,m<=50000

分析

如果是离线的话很显然直接维护一个桶然后上莫队就好了。

但如果强制在线的话……分块大法好!!!分块大法好!!!分块大法好!!!

预处理ans[i,j]表示第i块到第j块的答案,sum[i,j]表示i在前j块出现的次数,然后每次询问的时候对两端的块分别扫一遍即可。

记得用完桶之后要把桶清零。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100005
#define M 317
using namespace std;

int n,block,pos
,sta[M],end[M],ans[M][M],sum
[M],t
,a
,c,m;

int query(int l,int r)
{
if (pos[l]==pos[r])
{
int tot=0;
for (int i=l;i<=r;i++)
{
t[a[i]]++;
if (t[a[i]]%2==0) tot++;
else if (t[a[i]]>1) tot--;
}
for (int i=l;i<=r;i++)
t[a[i]]--;
return tot;
}
int tot=ans[pos[l]+1][pos[r]-1];
for (int i=l;i<=end[pos[l]];i++)
{
t[a[i]]++;
int w=t[a[i]]+sum[a[i]][pos[r]-1]-sum[a[i]][pos[l]];
if (w%2==0) tot++;
else if (w>1) tot--;
}
for (int i=sta[pos[r]];i<=r;i++)
{
t[a[i]]++;
int w=t[a[i]]+sum[a[i]][pos[r]-1]-sum[a[i]][pos[l]];
if (w%2==0) tot++;
else if (w>1) tot--;
}
for (int i=l;i<=end[pos[l]];i++)
t[a[i]]--;
for (int i=sta[pos[r]];i<=r;i++)
t[a[i]]--;
return tot;
}

int main()
{
scanf("%d%d%d",&n,&c,&m);
block=sqrt(n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pos[i]=(i+block-1)/block;
if (!sta[pos[i]]) sta[pos[i]]=i;
end[pos[i]]=i;
}
for (int i=1;i<=pos
;i++)
{
for (int j=i;j<=pos
;j++)
{
ans[i][j]=ans[i][j-1];
for (int k=sta[j];k<=end[j];k++)
{
t[a[k]]++;
if (t[a[k]]%2==0) ans[i][j]++;
else if (t[a[k]]>1) ans[i][j]--;
}
}
for (int j=sta[i];j<=n;j++)
t[a[j]]--;
}
for (int i=1;i<=n;i++)
sum[a[i]][pos[i]]++;
for (int i=1;i<=c;i++)
for (int j=1;j<=pos
;j++)
sum[i][j]+=sum[i][j-1];
int lastans=0;
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: