【BZOJ2821】作诗(Poetize) 分块

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

Source

  还没AC就写题解2333,原因是因为入BZ坑以来第二次遇到卡评测的事辣,虽然没法评测,遇到这种事莫名感兴趣XD。
  比较神的分块辣,比之前做的麻烦多了,一开始感觉弹飞绵羊思路挺有趣,一看这道题,强制在线,10^5,smg,看题解,脑冻好大啊,我自己肯定想不出,首先我们需要预处理出两个东西。
  1.f[i][j]:第i块到第j块中合法的个数。
  2.前缀和[i][j]:前i个汉字中j出现的个数,当然并不是用2维数组的来实现的,而是在结构体中以汉字为第一关键字,以所在序号为第二关键字排序,用的时候二分即可。
  这样,题目变得很明了了,查询时,对于同块或相邻块内的查询,直接暴力二分统计即可,若不在同一个块内,则开始直接ans=f[pos[l]+1][pos[r]-1](pos[]为所在块),也就是吧l,r之间的完整的块直接用f[][],剩下的暴力二分,注意细节。
  但是!!!跟着黄学长写,分成sqrt(n)块的我t了,要分成sqrt(n/logn)块,不知道哪里写残了,一定要写个分成sqrt(n)的版本出来。
  
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <cstring>
  5 #include <algorithm> 
  6 #define N 100010
  7 #define sN 1555
  8 #define inf 0x7fffffff
  9 using namespace std;
 10 struct data{int v,p;}b[N]; 
 11 int f[sN][sN],first[N],last[N],flag[N],temp[N],a[N],pos[N],L[sN],R[sN];
 12 int n,m,block,cnt,c;
 13 bool cmp(data a,data b) {if (a.v<b.v) return 1; else if (a.v==b.v && a.p<b.p) return 1; return 0;}
 14 inline int read()
 15 {
 16     char c;
 17     int ans=0;
 18     while ((c=getchar())==' ' || c=='
' || c=='
');
 19     ans=c-'0';
 20     while (isdigit(c=getchar())) ans=ans*10+c-'0';
 21     return ans;
 22 }
 23 void part1_pre()
 24 {
 25     for (int i=1;i<=cnt;i++)
 26     {
 27         int tot;
 28         for (int j=L[i];j<=n;j++) temp[a[j]]=0;
 29         tot=0;
 30         for (int j=L[i];j<=n;j++)
 31         {
 32             if (!(temp[a[j]]&1) && temp[a[j]]) tot--;
 33             temp[a[j]]++;
 34             if (!(temp[a[j]]&1)) tot++;
 35             f[i][pos[j]]=tot;
 36         }
 37     }
 38     for (int i=1;i<=n;i++)
 39     {
 40         b[i].v=a[i];
 41         b[i].p=i;
 42     }
 43     sort(b+1,b+n+1,cmp);
 44     for (int i=1;i<=n;i++)
 45     {
 46         if (!first[b[i].v]) first[b[i].v]=i;
 47         last[b[i].v]=i;
 48     }
 49 }
 50 int findup(int x,int v)
 51 {
 52     int tem=0,l=first[v],r=last[v];
 53     while (l<=r)
 54     {
 55         int mid=(l+r)>>1;
 56         if (x<b[mid].p) r=mid-1;
 57         else {l=mid+1;tem=mid;}
 58     }
 59     return tem;
 60 }
 61 int finddown(int x,int v)
 62 {
 63     int tem=inf,l=first[v],r=last[v];
 64     while (l<=r)
 65     {
 66         int mid=(l+r)>>1;
 67         if (x>b[mid].p) l=mid+1;
 68         else {r=mid-1;tem=mid;}
 69     }
 70     return tem;
 71 }
 72 int find(int x,int y,int v) {return max(findup(y,v)-finddown(x,v)+1,0);}
 73 int query(int x,int y)
 74 {
 75     int ans=0,t,t1;
 76     if (pos[x]==pos[y] || pos[x]+1==pos[y])
 77     {
 78         for (int i=x;i<=y;i++)
 79         {
 80             if (!flag[a[i]])
 81             {
 82                 t=find(x,y,a[i]);
 83                 if (!(t&1)) {ans++;flag[a[i]]=1;}
 84             }
 85         }
 86         for (int i=x;i<=y;i++) flag[a[i]]=0;
 87     }
 88     else
 89     {
 90         int l=L[pos[x]+1],r=R[pos[y]-1];
 91         ans=f[pos[x]+1][pos[y]-1];
 92         for (int i=x;i<l;i++)
 93         {
 94             if (!flag[a[i]])
 95             {
 96                 flag[a[i]]=1;
 97                 t=find(x,y,a[i]);t1=find(l,r,a[i]);
 98                 if (!(t&1)) 
 99                     {if ((t1&1) || !t1) ans++;}
100                 else   
101                     if (!(t1&1) && t1) ans--;
102             }
103         }
104         for (int i=r+1;i<=y;i++)
105         {
106             if (!flag[a[i]])
107             {
108                 flag[a[i]]=1;
109                 t=find(x,y,a[i]);t1=find(l,r,a[i]);
110                 if (!(t&1)) 
111                     {if ((t1&1) || !t1) ans++;}
112                 else
113                     if (!(t1&1) && t1) ans--;
114             }
115         }
116         for (int i=x;i<l;i++) flag[a[i]]=0;
117         for (int i=r+1;i<=y;i++) flag[a[i]]=0;
118     }
119     return ans;
120 }
121 int main()
122 {
123     int ans=0;
124     n=read();c=read();m=read();
125     block=sqrt((double)n/log((double)n)*log(2));
126     for (int i=1;i<=n;i++) a[i]=read();
127     if (n%block) cnt=n/block+1;
128     else cnt=n/block;
129     for (int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
130     for(int i=1;i<=cnt;i++)
131     L[i]=(i-1)*block+1,R[i]=i*block;
132     R[cnt]=n;
133     part1_pre();
134     for (int i=1;i<=m;i++)
135     {
136          
137         int l=read(),r=read();
138         int x=(l+ans)%n+1,y=(r+ans)%n+1;
139         if (x>y) swap(x,y);
140         ans=query(x,y);
141         printf("%d
",ans);
142     }
143     return 0;
144 }
sqrt(n/logn)版本
—Anime Otaku Save The World.
原文地址:https://www.cnblogs.com/DMoon/p/5270264.html