[BZOJ2821]作诗(Poetize)
2821: 作诗(Poetize)
Time Limit: 50 Sec Memory Limit: 128 MB Submit: 3178 Solved: 925 [Submit][Status][Discuss]Description
神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗。由于时间紧迫,SHY作完诗
之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一
些汉字构成诗。因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次。而且SHY认
为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!)。于是SHY请LYD安排选
法。LYD这种傻×当然不会了,于是向你请教……问题简述:N个数,M组询问,每次问[l,r]中有多少个数出现正偶
数次。
Input
输入第一行三个整数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]。
Output
输出共m行,每行一个整数,第i个数表示SHY第i次能选出的汉字的最多种类数。
Sample Input
5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
Sample Output
2
0
0
0
1
0
0
0
1
HINT
对于100%的数据,1<=n,c,m<=10^5
类似于区间众数的做法
把块到块的答案预处理出来,然后在查询时暴力两端的数
根据两端的数在区间出现的次数以及整块里的次数来判断对答案的影响
绝对不要memset,绝对不要!!
#include <cmath> #include <cstdio> #include <algorithm> using namespace std; inline int readint(){ int n = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch <= '9' && ch >= '0'){ n = (n << 1) + (n << 3) + ch - '0'; ch = getchar(); } return n; } const int maxn = 100000 + 10; int n, c, m; int a[maxn], belong[maxn], block_size; int f[1500][1500], tax[maxn]; inline void work(int x){ int ans = 0; for(int i = (x - 1) * block_size + 1; i <= n; i++) tax[a[i]] = 0; for(int i = (x - 1) * block_size + 1; i <= n; i++){ tax[a[i]]++; if((tax[a[i]] & 1) && tax[a[i]] != 1) ans--; if(!(tax[a[i]] & 1)) ans++; f[x][belong[i]] = ans; } } struct Node{int pos, val;}no[maxn]; inline bool cmp(const Node &a, const Node &b){ return a.val == b.val ? a.pos < b.pos : a.val < b.val; } int first[maxn], last[maxn]; inline int upper(int x, int k){ int l = first[x], r = last[x], mid, ret = 0; while(l <= r){ mid = l + r >> 1; if(no[mid].pos > k) r = mid - 1; else{ ret = mid; l = mid + 1; } } return ret; } inline int lower(int x, int k){ int l = first[x], r = last[x], mid, ret = 66662333; while(l <= r){ mid = l + r >> 1; if(no[mid].pos < k) l = mid + 1; else{ ret = mid; r = mid - 1; } } return ret; } inline int Count(int l, int r, int x){ return max(upper(x, r) - lower(x, l) + 1, 0); } bool mark[maxn] = {false}; inline int Query(int l, int r){ int ans = 0; if(belong[r] - belong[l] <= 1){ for(int t, i = l; i <= r; i++){ if(mark[a[i]]) continue; mark[a[i]] = true; t = Count(l, r, a[i]); if(!(t & 1) && t) ans++; } for(int i = l; i <= r; i++) mark[a[i]] = false; return ans; } else{ int ll = belong[l] * block_size + 1, rr = (belong[r] - 1) * block_size; ans = f[belong[ll]][belong[rr]]; for(int x, y, i = l; i < ll; i++){ if(mark[a[i]]) continue; mark[a[i]] = true; x = Count(l, r, a[i]); y = Count(ll, rr, a[i]); if((x & 1)){ if(!(y & 1) && y) ans--; } else if(x && (!y || (y & 1))) ans++; } for(int x, y, i = rr + 1; i <= r; i++){ if(mark[a[i]]) continue; mark[a[i]] = true; x = Count(l, r, a[i]); y = Count(ll, rr, a[i]); if((x & 1)){ if(!(y & 1) && y) ans--; } else if(x && (!y || (y & 1))) ans++; } for(int i = l; i < ll; i++) mark[a[i]] = false; for(int i = rr + 1; i <= r; i++) mark[a[i]] = false; return ans; } } int main(){ n = readint(); c = readint(); m = readint(); block_size = 1.0 * n / sqrt(log2(n + 1) * m); for(int i = 1; i <= n; i++) belong[i] = (i - 1) / block_size + 1; for(int i = 1; i <= n; i++){ no[i].val = a[i] = readint(); no[i].pos = i; } sort(no + 1, no + n + 1, cmp); for(int i = 1; i <= n; i++){ if(!first[no[i].val]) first[no[i].val] = i; last[no[i].val] = i; } for(int i = 1; i <= n; i++) work(i); for(int l, r, ans = 0, i = 1; i <= m; i++){ l = (readint() + ans) % n + 1; r = (readint() + ans) % n + 1; if(l > r) swap(l, r); printf("%d\n", ans = Query(l, r)); } return 0; }