[BZOJ2821]作诗(分块)
题意
N个数,M组询问,每次问[l,r]中有多少个数出现正偶数次
对于100%的数据,1≤n,c,m≤105
题解
(传说lyd省选的时候看错题 把题看成这个了 从此又多了一道分块神题)
把N个数分成sqrt(n)块,预处理d[i][j]表示第i块起点到第j块末尾的答案 枚举起点i,并维护一个数组记录每个数到目前为止出现的次数,从偶变奇、从奇变偶时相应增减答案。 把每个数在数列中出现的位置从小到大排序后放入到一个数组Arr中备用。 读入每个询问[l,r]。如果l和r在同一个块中暴力即可,否则设l所在块的末尾为l’,r所在块的起点为r’,[l’+1,r’-1]的答案已经预处理出。扫描l~l’, r’~r的所有数,统计每个数出现的次数cnt,第一次出现时把它加入队列。 对于队列中的每个数,在数组Arr中二分l’+1和r’-1,得到在[l’+1,r’-1]中出现的次数k。通过对k和当前队列中的数的cnt进行奇偶性讨论更新答案
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #include<vector> 7 using namespace std; 8 const int N=100100; 9 vector<int> vec[N]; 10 int n,c,m,a[N],block[N],Block,R[1600],L[1600],cnt[N],f[1600][1600],ans,stack[N],top; 11 inline int read(){ 12 int f=1;int x=0;char ch=getchar(); 13 while(ch<'0'||ch>'9'){ 14 if(ch=='-')f=-1; 15 ch=getchar(); 16 } 17 while(ch>='0'&&ch<='9'){ 18 x=(x<<3)+(x<<1)+ch-'0'; 19 ch=getchar(); 20 } 21 return x*f; 22 } 23 int find1(int x,int y){ 24 int l=0;int r=vec[x].size()-1; 25 int tmp=-99999; 26 while(l<=r){ 27 int mid=(l+r)>>1; 28 if(vec[x][mid]<=y){ 29 tmp=mid; 30 l=mid+1; 31 } 32 else r=mid-1; 33 } 34 return tmp; 35 } 36 int find2(int x,int y){ 37 int l=0;int r=vec[x].size()-1; 38 int tmp=9999; 39 while(l<=r){ 40 int mid=(l+r)>>1; 41 if(vec[x][mid]>=y){ 42 tmp=mid; 43 r=mid-1; 44 } 45 else l=mid+1; 46 } 47 return tmp; 48 } 49 int main(){ 50 n=read();c=read();m=read(); 51 Block=sqrt(n); 52 for(int i=1;i<=n;i++){ 53 a[i]=read(); 54 vec[a[i]].push_back(i); 55 block[i]=(i-1)/Block+1; 56 if(!L[block[i]])L[block[i]]=i; 57 R[block[i]]=i; 58 } 59 for(int i=1;i<=block[n];i++){ 60 int tot=0; 61 for(int j=L[i];j<=n;j++){ 62 if(!(cnt[a[j]]&1)&&cnt[a[j]])tot--; 63 cnt[a[j]]++; 64 if(!(cnt[a[j]]&1))tot++; 65 f[i][block[j]]=tot; 66 } 67 for(int j=L[i];j<=n;j++){ 68 cnt[a[j]]=0; 69 } 70 } 71 while(m--){ 72 int l,r; 73 l=read();r=read(); 74 l=(l+ans)%n+1;r=(r+ans)%n+1; 75 if(l>r)swap(l,r); 76 if(block[l]+1>=block[r]){ 77 ans=0; 78 for(int i=l;i<=r;i++){ 79 cnt[a[i]]++; 80 if(cnt[a[i]]==1)continue; 81 if(cnt[a[i]]&1)ans--; 82 else ans++; 83 } 84 for(int i=l;i<=r;i++) 85 cnt[a[i]]=0; 86 } 87 else{ 88 ans=f[block[l]+1][block[r]-1]; 89 top=0; 90 for(int i=l;i<=R[block[l]];i++){ 91 cnt[a[i]]++; 92 if(cnt[a[i]]==1)stack[++top]=a[i]; 93 } 94 for(int i=L[block[r]];i<=r;i++){ 95 cnt[a[i]]++; 96 if(cnt[a[i]]==1)stack[++top]=a[i]; 97 } 98 while(top){ 99 int z=stack[top--]; 100 int tmp=max(find1(z,L[block[r]]-1)-find2(z,R[block[l]]+1)+1,0); 101 if(tmp==0){ 102 if(cnt[z]%2==0)ans++; 103 } 104 else{ 105 if(tmp&1){if(cnt[z]&1)ans++;} 106 else {if(cnt[z]&1)ans--;} 107 } 108 cnt[z]=0; 109 } 110 } 111 printf("%d\n",ans); 112 } 113 return 0; 114 }