洛谷传送门
BZOJ传送门
题目描述
神犇SJY虐完HEOI之后给傻×LYD出了一题:
SHY是T国的公主,平时的一大爱好是作诗。
由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为 N N 的文章,阅读次,每次只阅读其中连续的一段 [l,r] [ l , r ] ,从这一段中选出一些汉字构成诗。因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在 [l,r] [ l , r ] 里出现了正偶数次。而且SHY认为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!)。于是SHY请LYD安排选法。
LYD这种傻×当然不会了,于是向你请教……
问题简述: N N 个数,组询问,每次问 [l,r] [ l , r ] 中有多少个数出现正偶数次。
输入输出格式
输入格式:
输入第一行三个整数 n n 、以及 m m 。表示文章字数、汉字的种类数、要选择次。
第二行有 n n 个整数,每个数在 [1,c] [ 1 , c ] 间,代表一个编码为 Ai A i 的汉字。
接下来 m m 行每行两个整数和 r r ,设上一个询问的答案为(第一个询问时 ans=0 a n s = 0 ),令 L=(l+ans)modn+1 L = ( l + a n s ) mod n + 1 , R=(r+ans)mod n+1 R = ( r + a n s ) mod n + 1 ,若 L>R L > R ,交换 L L 和,则本次询问为 [L,R] [ L , R ] 。
输出格式:
输出共 m m 行,每行一个整数,第个数表示SHY第 i i 次能选出的汉字的最多种类数。
输入输出样例
输入样例#1:
5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
输出样例#1:
2
0
0
0
1
说明
对于100%的数据,
解题分析
这道题用线段树的话区间信息不好合并, 于是大力分块…
我们可以先 O(NN−−√) O ( N N ) 预处理块内的每个颜色出现的次数, O(NN−−√) O ( N N ) 预处理块 A A 到块的答案。询问时边角暴力, 加上中间一块预处理的答案即可。
详见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdlib>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 100050
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
const int UP = std::sqrt(MX) + 1;
int dot, siz, q, ctyp, bd, lastans;
int bel[MX], sum[333][MX], ans[333][333], cnt[MX], dat[MX];
IN int query(R int lef, R int rig)
{
lastans = 0;
if(lef > rig) std::swap(lef, rig);
int l = bel[lef], r = bel[rig];
if(r - l <= 1)//相邻块或同块直接暴力
{
for (R int i = lef; i <= rig; ++i)
{
++cnt[dat[i]];
if(!(cnt[dat[i]] & 1)) ++lastans;
else if(cnt[dat[i]] > 2) --lastans;
}
for (R int i = lef; i <= rig; ++i) --cnt[dat[i]];
return lastans;
}
lastans = ans[l + 1][r - 1];
int lb = l * siz, buf;
for (R int i = lef; i <= lb; ++i)//两边分别暴力
{
++cnt[dat[i]];
buf = cnt[dat[i]] + sum[r - 1][dat[i]] - sum[l][dat[i]];
if(!(buf & 1)) ++lastans;
else if(buf > 2) --lastans;
}
for (R int i = (r - 1) * siz + 1; i <= rig; ++i)
{
++cnt[dat[i]];
buf = cnt[dat[i]] + sum[r - 1][dat[i]] - sum[l][dat[i]];
if(!(buf & 1)) ++lastans;
else if(buf > 2) --lastans;
}
for (R int i = lef; i <= lb; ++i) --cnt[dat[i]];
for (R int i = (r - 1) * siz + 1; i <= rig; ++i) --cnt[dat[i]];
return lastans;
}
int main(void)
{
int cot, a, b;
in(dot), in(ctyp), in(q); siz = std::sqrt(dot) + 1;
for (R int i = 1; i <= dot; ++i)
{
in(dat[i]); bel[i] = (i - 1) / siz + 1;
++sum[bel[i]][dat[i]];
} bd = bel[dot];
for (R int i = 1; i <= ctyp; ++i)
for (R int j = 1; j <= bd; ++j) sum[j][i] += sum[j - 1][i];//预处理每块字符数量的前缀和
for (R int i = 1; i <= bd; ++i)
{
cot = 0;//预处理块间的答案
for (R int j = (i - 1) * siz + 1; j <= dot; ++j)
{
++cnt[dat[j]];
if(!(cnt[dat[j]] & 1)) ++cot;
else if(cnt[dat[j]] > 2) --cot;
ans[i][bel[j]] = cot;
}
for (R int j = (i - 1) * siz + 1; j <= dot; ++j) --cnt[dat[j]];
}
W (q--)
{
in(a), in(b);
a = (a + lastans) % dot + 1, b = (b + lastans) % dot + 1;
printf("%d\n", query(a, b));
}
}