[BZOJ2821]作诗(Poetize)

[BZOJ2821]作诗(Poetize)

试题描述

神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗。由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一些汉字构成诗。因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次。而且SHY认为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!)。于是SHY请LYD安排选法。LYD这种傻×当然不会了,于是向你请教……问题简述:N个数,M组询问,每次问[l,r]中有多少个数出现正偶数次。

输入

输入第一行三个整数n、c以及m。表示文章字数、汉字的种类数、要选择M次。第二行有n个整数,每个数Ai在[1, c]间,代表一个编码为Ai的汉字。接下来m行每行两个整数l和r,设上一个询问的答案为ans(第一个询问时ans=0),令L=(l+ans)mod n+1, R=(r+ans)mod n+1,若L>R,交换L和R,则本次询问为[L,R]。

输出

输出共m行,每行一个整数,第i个数表示SHY第i次能选出的汉字的最多种类数。

输入示例

5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5

输出示例

2
0
0
0
1

数据规模及约定

对于100%的数据,1<=n,c,m<=10^5

题解

分块,统计出 f[i][j] 表示第 i 个块到第 j 个块中出现正偶次的数有多少个。对于一个询问 [ql, qr],我们搞出那一段连续整块的答案,然后对于首尾零散的部分我们依次把所有出现的颜色统计一下它在整块那一段连续整块中出现次数的奇偶性和它在 [ql, qr] 中出现次数的奇偶性加加减减调整答案就好了。

这题做法其实和区间众数很类似。

这题块的大小要开小点(sqrt(n / log2(n) )),否则会 T 得很惨。。。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
	if(Head == Tail) {
		int l = fread(buffer, 1, BufferSize, stdin);
		Tail = (Head = buffer) + l;
	}
	return *Head++;
}
int read() {
	int x = 0, f = 1; char c = Getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
	return x * f;
}

#define maxn 100010
#define maxbl 2010

int n, A[maxn], tot[maxn];

int cb, st[maxbl], en[maxbl], even[maxbl][maxbl], blid[maxn];
vector <int> pos[maxn];

int calc(int l, int r, int col) {
	if(l > r) return 0;
	return upper_bound(pos[col].begin(), pos[col].end(), r) - lower_bound(pos[col].begin(), pos[col].end(), l);
}
int appcol[maxn], capp, clo[maxn];
int query(int ql, int qr, int tag) {
	if(blid[ql] == blid[qr]) {
		int tmp = 0;
		for(int i = ql; i <= qr; i++) {
			if(clo[A[i]] != tag) clo[A[i]] = tag, tot[A[i]] = 0;
			tot[A[i]]++;
			if((tot[A[i]] & 1) && tot[A[i]] > 1) tmp--;
			if(!(tot[A[i]] & 1)) tmp++;
		}
		return tmp;
	}
	int bl = blid[ql], br = blid[qr], tmp = even[bl+1][br-1];
	capp = 0;
	for(int i = ql; i <= en[bl]; i++) {
		if(clo[A[i]] != tag) clo[A[i]] = tag, tot[A[i]] = 0;
		if(!tot[A[i]]) appcol[++capp] = A[i];
		tot[A[i]] = 1;
	}
	for(int i = st[br]; i <= qr; i++) {
		if(clo[A[i]] != tag) clo[A[i]] = tag, tot[A[i]] = 0;
		if(!tot[A[i]]) appcol[++capp] = A[i];
		tot[A[i]] = 1;
	}
	for(int i = 1; i <= capp; i++) {
		int appt = calc(ql, qr, appcol[i]), appt_bl = calc(st[bl+1], en[br-1], appcol[i]);
		if(!(appt & 1) && ((appt_bl & 1) || !appt_bl)) tmp++;
		if((appt & 1) && (!(appt_bl & 1) && appt_bl)) tmp--;
	}
	return tmp;
}

int main() {
	n = read(); int C = read(), q = read();
	for(int i = 1; i <= n; i++) A[i] = read();
	
	int m = 50;
	for(int i = 1; i <= n; i++) {
		int bl = (i - 1) / m + 1; cb = max(cb, bl);
		blid[i] = bl;
		if(!st[bl]) st[bl] = i; en[bl] = i;
		pos[A[i]].push_back(i);
	}
	for(int i = 1; i <= cb; i++) {
		memset(tot, 0, sizeof(tot));
		int tmp = 0;
		for(int j = st[i]; j <= n; j++) {
			tot[A[j]]++;
			if((tot[A[j]] & 1) && tot[A[j]] > 1) tmp--;
			if(!(tot[A[j]] & 1)) tmp++;
			if(j == n || blid[j] != blid[j+1]) even[i][blid[j]] = tmp;
		}
	}
	
	int lstans = 0;
	while(q--) {
		int l = (read() + lstans) % n + 1, r = (read() + lstans) % n + 1;
		if(l > r) swap(l, r);
		printf("%d\n", lstans = query(l, r, q + 1));
	}
	
	return 0;
}

 

posted @ 2017-04-30 12:25  xjr01  阅读(206)  评论(0编辑  收藏  举报