首页 > 代码库 > BZOJ2821作诗【分块】

BZOJ2821作诗【分块】

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

Sample Output

2

0

0

0

1

HINT

对于100%的数据,1<=n,c,m<=10^5

有趣的分块...

分成sqrt(n)个块以后处理处i到j个块的答案,将原序列排序,这样整块的两边的元素可以在整块区间中查找相同元素检测对答案的影响.

要注意计算影响时什么时候+、-,要判断原来有没有。。。无力吐槽

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<iostream>
  6 using namespace std;
  7 const int N=100005;
  8 const int M=350;
  9 struct node{
 10     int a,p;
 11 }e[N];
 12 int pos[N],d[N],S,map[M][M],le[M*3],ans=0,a,b,size=0;
 13 int num[N],x[N],y[N];
 14 inline bool cmp(node x,node y)
 15 {
 16     if(x.a!=y.a) return x.a<y.a;
 17     return x.p<y.p;
 18 }
 19 inline int find(int u,int l,int r)
 20 {
 21     int cnt=0;
 22     for(int i=x[u];i<=y[u];i++)
 23     {
 24         if(l<=e[i].p&&e[i].p<=r) cnt++;
 25         if(e[i].p>r) break;
 26     }
 27     return cnt;
 28 }
 29 inline void get_ans(int l,int r)
 30 {
 31     sort(le+1,le+size+1);
 32     int cnt=0,k;
 33     for(int i=1;i<=size;i++)
 34     {
 35         cnt++;
 36         if(le[i]!=le[i+1])
 37         {
 38             k=find(le[i],l,r);
 39             if(k%2==0&&k&&cnt%2==1) ans--;
 40             else if(k%2==1&&cnt%2==1) ans++;
 41             else if(k==0&&cnt%2==0) ans++;
 42             cnt=0;
 43         }
 44     }
 45 }
 46 int main()
 47 {
 48     int n,m,c,t,cnt,l,r;
 49     int k=0;
 50     scanf("%d%d%d",&n,&c,&m);
 51     S=(int)sqrt(n);
 52     for(int i=1;i<=n;i++)
 53     {
 54         scanf("%d",&d[i]);
 55         e[i].a=d[i];
 56         e[i].p=i;
 57         pos[i]=(i-1)/S+1;
 58     }
 59     t=pos[n];
 60     sort(e+1,e+n+1,cmp);
 61     x[e[1].a]=1;
 62     for(int i=1;i<=n;i++) if(e[i].a!=e[i+1].a)
 63     {
 64         y[e[i].a]=i;
 65         x[e[i+1].a]=i+1;
 66     }
 67     for(int i=1;i<=t;i++)
 68     {
 69         memset(num,0,sizeof(num));
 70         cnt=0;
 71         for(int j=(i-1)*S+1;j<=n;j++)
 72         {
 73             num[d[j]]++;
 74             if(num[d[j]]%2==0) cnt++;
 75             else if(num[d[j]]>1&&num[d[j]]%2==1) cnt--;
 76             if(pos[j]!=pos[j+1]) map[i][pos[j]]=cnt;
 77         }
 78     }
 79     while(m--)
 80     {
 81         scanf("%d%d",&l,&r);
 82         l=(l+ans)%n+1;
 83         r=(r+ans)%n+1;
 84         if(l>r) swap(l,r);
 85         if(pos[l]==pos[r]||pos[l]+1==pos[r])
 86         {
 87             memset(num,0,sizeof(num));
 88             ans=0;
 89             for(int i=l;i<=r;i++)
 90             {
 91                 num[d[i]]++;
 92                 if(num[d[i]]%2==0) ans++;
 93                 else if(num[d[i]]>1&&num[d[i]]%2==1) ans--;
 94             }
 95             printf("%d\n",ans);
 96             continue;
 97         }
 98         memset(le,0,sizeof(le));
 99         size=0;
100         if(pos[l]==pos[l-1])
101         {
102             a=pos[l]+1;
103             while(pos[l]==pos[l-1]&&l<=n) le[++size]=d[l],l++;
104         }
105         else a=pos[l];
106         if(pos[r]==pos[r+1])
107         {
108             b=pos[r]-1;
109             while(pos[r]==pos[r+1]&&r>0) le[++size]=d[r],r--;
110         }
111         else b=pos[r];
112         ans=map[a][b];
113         get_ans(l,r);
114         printf("%d\n",ans);
115     }
116     return 0;
117 }

 

BZOJ2821作诗【分块】