YZOJ P3371 简单计数问题
时间限制:3000MS 内存限制:262144KB
难度: \(6.0\) 出题人:zzx
-
问题描述
给定正整数序列 \(a[1], a[2], \cdots , a[n]\),你需要依次解决 \(m\) 个询问,每个询问用两个正整数 \(L, R\) 描述, 请求出有多少个数在 \(a[L],a[L+1],\cdots,a[R]\) 中出现正偶数次。
-
编程任务
求出每个查询的结果。
-
数据输入
输入第一行四个整数 \(n\)、\(c\)、\(m\) 以及 \(t\) 。
第二行 \(n\) 个整数 \(a[1],a[2],\cdots,a[n]\),每个数在 \([1,c]\) 间。
接下来 \(m\) 行每行两个整数 \(l\) 和 \(r\),设上一个询问的答案为 \(ans\) (第一个询问时 \(ans=0\) ),令 \(L=(l+t \times ans) \bmod n+1, R=(r+t \times ans) \bmod n+1\),若 \(L>R\),交换 \(L\) 和 \(R\),则本次询问为 \([L,R]\) 。
-
结果输出
对于每个询问, 输出一行对应的答案。
-
样例输入
1 2 3 4 5 6 7 |
5 3 5 1 1 2 2 3 1 0 4 1 2 2 2 2 3 3 5 |
-
样例输出
1 2 3 4 5 |
2 0 0 0 1 |
-
数据范围
对于 \(50\%\) 的数据,有 \(t=0\) 。
对于另外 \(50\%\) 的数据,有 \(t=1\) 。
对于 \(100\%\) 的数据,\(n, m, c \leq 100000\)。
首先对于 \(t=0\) 的点,也就意味着离线,直接一个裸的莫队即可。
那本题的正解是。。。。。。在。。在线。。。在线莫队?
其实题解里写的就是【在线莫队】,但是我个人认为就是一个裸的分块。
把序列分块,记录 块内各种颜色出现次数的桶 的前缀和,然后再记录 \(ans_{l, r}\) 表示块 \(l\) 到 块 \(r\) 之间的答案。
桶的前缀和可以 \(O(c\sqrt n)\) 预处理,之后处理 \(ans\) 也可以做到 \(O(n\sqrt n)\) 。
那么现在对于一个询问 \([L, R]\):
若 \([L, R]\) 没有跨过连续的两个块,那么直接暴力算一下即可;
若 \([L, R]\) 跨过了至少两个连续的块,那么找到 \(L\) 之后的一个块的分界点 \(x\) 以及 \(R\) 之前的一个块的分界点 \(y\),答案先加上 \(ans_{x, y}\) 。对于剩下的数再开一个桶暴力加,但是注意的是一个数 \(c\) 出现的次数为 这个桶内的次数+中间跨过的块中 \(c\) 出现的次数(已经前缀和预处理了)。
时间复杂度 \(O((n+c)\sqrt n)\) 。(我跑垫底了)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #define _min(_a_,_b_) ((_a_)<(_b_)?(_a_):(_b_)) #ifdef ONLINE_JUDGE char __B[1<<15],*__S=__B,*__T=__B; #define getchar() (__S==__T&&(__T=(__S=__B)+fread(__B,1,1<<15,stdin),__S==__T)?EOF:*__S++) #endif inline int getnum() { register char c=0; while(!(c>='0' && c<='9')) c=getchar(); register int a=0; while(c>='0' && c<='9') { a*=10;a+=c-'0'; c=getchar(); } return a; } int BlockSize,BlockNum; int _bpos[105050],_bleft[350],_bright[350]; #define GetBlockPos(_p_) (_bpos[_p_]) #define GetBlockLeft(_w_) (_bleft[_w_]) #define GetBlockRight(_w_) (_bright[_w_]) /*#define GetBlockPos(_p_) (((_p_)-1)/BlockSize+1) #define GetBlockLeft(_w_) (((_w_)-1)*BlockSize+1) #define GetBlockRight(_w_) _min((_w_)*BlockSize,N)*/ int a[105050]; int gans[350][350],gbucket[350][105050]; //inline void AddNum(int&ans,int bucket[],register int a,register int offset=0) #define AddNum(_ans,_bucket,_a,_offset) \ { \ _bucket[_a]++; \ if((_offset+_bucket[_a])%2==0) \ _ans++; \ else if(_offset+(_bucket[_a])!=1) \ _ans--; \ } //inline void DelNum(int&ans,int bucket[],register int a,register int offset=0) #define DelNum(_ans,_bucket,_a,_offset) \ { \ _bucket[_a]--; \ if((_offset+_bucket[_a])%2!=0) \ _ans--; \ else if(_offset+_bucket[_a]) \ _ans++; \ } int main() { register int N=getnum(),C=getnum(),M=getnum(),T=getnum(); for(register int i=1;i<=N;i++) a[i]=getnum(); BlockSize=__builtin_sqrt(N),BlockNum=N/BlockSize+(N%BlockSize!=0); _bleft[1]=1; for(register int i=1,tb=1;i<=N;i++) { _bpos[i]=tb; if(i%BlockSize == 0) _bright[tb++]=i,_bleft[tb]=i+1; } for(register int i=1;i<=N;i++) { register int tb=GetBlockPos(i),tbp=GetBlockPos(i-1); if(tb != tbp) memcpy(&gbucket[tb][0],&gbucket[tbp][0],sizeof(int)*(C+1)),gans[1][tb]=gans[1][tbp]; AddNum(gans[1][tb],gbucket[tb],a[i],0); } for(register int i=2;i<=BlockNum;i++) { register int lpos=GetBlockLeft(i); static int tbucket[105050]; register int tans=0; for(register int j=lpos;j<=N;j++) { AddNum(tans,tbucket,a[j],0); register int tb=GetBlockPos(j),tbn=GetBlockPos(j+1); if(tb != tbn) gans[i][tb]=tans; } gans[i][BlockNum]=tans; for(register int j=lpos;j<=N;j++) DelNum(tans,tbucket,a[j],0); } register int lastans=0; for(register int i=1;i<=M;i++) { register int l=getnum(),r=getnum(); l=(l+T*lastans)%N+1,r=(r+T*lastans)%N+1; if(l>r) l^=r^=l^=r; register int lb=GetBlockPos(l)+1,rb=GetBlockPos(r)-1; static int tbucket[105050]; register int tans=gans[lb][rb]; if(lb>rb) { for(register int i=l;i<=r;i++) AddNum(tans,tbucket,a[i],0); printf("%d\n",lastans=tans); for(register int i=l;i<=r;i++) DelNum(tans,tbucket,a[i],0); continue; } register int lrpos=GetBlockRight(lb-1),rlpos=GetBlockLeft(rb+1); for(register int i=l;i<=lrpos;i++) AddNum(tans,tbucket,a[i],gbucket[rb][a[i]]-gbucket[lb-1][a[i]]); for(register int i=rlpos;i<=r;i++) AddNum(tans,tbucket,a[i],gbucket[rb][a[i]]-gbucket[lb-1][a[i]]); printf("%d\n",lastans=tans); for(register int i=l;i<=lrpos;i++) DelNum(tans,tbucket,a[i],0); for(register int i=rlpos;i<=r;i++) DelNum(tans,tbucket,a[i],0); } return 0; } |