bzoj2821 -- 分块
将序列分块。
令f[i][j]表示第i块到第j块的答案,可以O(n*sqrt(n))统计出来。
令sum[i][j]表示前i块值为j的数出现了几次。每次询问暴力统计零散的数对答案的贡献就可以了。
具体见代码
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 inline char nc(){ 8 static char buf[100000],*p1=buf,*p2=buf; 9 if(p1==p2){ 10 p2=(p1=buf)+fread(buf,1,100000,stdin); 11 if(p1==p2)return EOF; 12 } 13 return *p1++; 14 } 15 inline void Read(int& x){ 16 char c=nc(); 17 for(;c<'0'||c>'9';c=nc()); 18 for(x=0;c>='0'&&c<='9';x=(x<<1)+(x<<3)+c-48,c=nc()); 19 } 20 char ss[30]; 21 int Len; 22 inline void Print(int x){ 23 if(x==0)putchar(48); 24 for(Len=0;x;x/=10)ss[++Len]=x%10; 25 for(;Len;)putchar(ss[Len--]+48);putchar('\n'); 26 } 27 #define N 100010 28 #define Sn 320 29 int i,j,k,n,m,b[N],Cnt,x,y,Sum[Sn][N],a[N],s,c,f[Sn][Sn],t[N],Ans,A[N],Top,l[N],r[N]; 30 int main() 31 { 32 Read(n);Read(c);Read(m); 33 s=sqrt((double)n);Cnt=(n-1)/s+1; 34 for(i=1;i<=n;i++){ 35 Read(a[i]);b[i]=(i-1)/s+1; 36 for(j=b[i];j<=Cnt;j++)Sum[j][a[i]]++; 37 r[b[i]]=i; 38 } 39 for(i=1;i<=Cnt;i++)l[i]=r[i-1]+1; 40 for(i=1;i<=Cnt;i++){ 41 memset(t,0,sizeof(t));x=0; 42 for(j=i;j<=Cnt;j++){ 43 for(k=l[j];k<=r[j];k++) 44 if(t[a[k]]++)x+=(t[a[k]]&1)?-1:1; 45 f[i][j]=x; 46 } 47 } 48 while(m--){ 49 Read(x);Read(y); 50 x=(x+Ans)%n+1;y=(y+Ans)%n+1; 51 if(x>y)swap(x,y); 52 if(b[x]==b[y]){ 53 Ans=Top=0; 54 for(i=x;i<=y;i++)A[++Top]=a[i]; 55 sort(A+1,A+Top+1); 56 for(i=j=1;i<=Top;i=j+1){ 57 while(A[j+1]==A[i]&&j<Top)j++; 58 if((j-i+1)%2==0)Ans++; 59 } 60 Print(Ans); 61 continue; 62 } 63 Ans=f[b[x]+1][b[y]-1];Top=0; 64 for(i=x;b[i]==b[x];i++)A[++Top]=a[i]; 65 for(i=y;b[i]==b[y];i--)A[++Top]=a[i]; 66 sort(A+1,A+Top+1); 67 for(i=j=1;i<=Top;i=j+1){ 68 while(A[j+1]==A[i]&&j<Top)j++; 69 if((j-i+1)%2==0){ 70 if(Sum[b[y]-1][A[i]]-Sum[b[x]][A[i]]==0)Ans++; 71 }else if((Sum[b[y]-1][A[i]]-Sum[b[x]][A[i]])%2==1)Ans++;else 72 if(Sum[b[y]-1][A[i]]-Sum[b[x]][A[i]]>0)Ans--; 73 } 74 Print(Ans); 75 } 76 return 0; 77 }