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 }
bzoj2821

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值