分块算法初探 AcWing249 蒲公英
作者:互联网
https://www.acwing.com/problem/content/description/251/
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
为了简化起见,我们把所有的蒲公英看成一个长度为 n 的序列a1,a2,…,an,其中ai为一个正整数,表示第 i 棵蒲公英的种类编号。
而每次询问一个区间 [l,r] ,你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
输入格式
第一行两个整数n,m,表示有 n 株蒲公英,m 次询问。
接下来一行 n 个空格隔开的整数aiai,表示蒲公英的种类。
再接下来 m 行每行两个整数l0,r0,我们令上次询问的结果为 x(如果这是第一次询问,则 x=0)。
令l=(l0+x-1) mod n+1,r=(r0+x-1) mod n+1,如果l>r,则交换l,r。
最终的询问区间为[l,r]。
输出格式
输出 m 行。
每行一个整数,表示每次询问的结果。
数据范围
1≤n≤40000,
1≤m≤50000,
1≤ai≤109
输入样例:
6 3
1 2 3 2 1 2
1 5
3 6
1 5
输出样例:
1
2
1
思路:
纯按照书(《算法竞赛进阶指南》)上的方法。
N:蒲公英的数量(序列长度),M:询问次数,T:分块数量。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 typedef long long ll; 7 using namespace std; 8 9 const int N=5e4+5; 10 11 int a[N],a2[N];//数组a2拷贝数组a。 12 int b[N];//离散化数据数组。 13 int pos[N];//元素所在的分块的编号。 14 int cou[N];//后面算答案时需要用到的count数组。 15 int l[N],r[N];//分块的左,右端点。 16 int sum[N][40];分块中某种编号的蒲公英数量的前缀和。 17 int num[N][40][40];//num[i][j][k]:分块j到分块k中种类i的蒲公英的数量。 18 int most[40][40],mostn[40][40];//分块中最多的蒲公英种类的数量以及最多的种类的编号。 19 int n,m,cnt=0;//cnt:出现的蒲公英的种类数。 20 21 void discrete() { 22 sort(a2+1,a2+n+1); 23 for(int i=1;i<=n;i++) { 24 if(i==1||a2[i]!=a2[i-1]) { 25 b[++cnt]=a2[i]; 26 } 27 } 28 } 29 30 int query(int x) { 31 return lower_bound(b+1,b+cnt+1,x)-b; 32 } 33 34 int main() { 35 scanf("%d%d",&n,&m); 36 for(int i=1;i<=n;i++) { 37 scanf("%d",&a[i]); 38 a2[i]=a[i]; 39 } 40 discrete();//离散化 41 for(int i=1;i<=n;i++) { 42 a[i]=query(a[i]); 43 } 44 int block=pow((double)n,0.33);//分块 45 int len=n/block; 46 for(int i=1;i<=block;i++) { 47 l[i]=(i-1)*len+1; 48 r[i]=i*len; 49 } 50 if(r[block]<n) { 51 block++;l[block]=r[block-1]+1;r[block]=n; 52 } 53 for(int i=1;i<=block;i++) {//预处理数据 54 for(int j=1;j<=cnt;j++) { 55 sum[j][i]=sum[j][i-1]; 56 } 57 for(int j=l[i];j<=r[i];j++) { 58 pos[j]=i; 59 sum[a[j]][i]++; 60 } 61 } 62 for(int i=1;i<=block;i++) { 63 for(int j=i;j<=block;j++) { 64 int MAX=0,maxn; 65 for(int k=1;k<=cnt;k++) { 66 num[k][i][j]=sum[k][j]-sum[k][i-1]; 67 int tmp=num[k][i][j]; 68 if(MAX<tmp||MAX==tmp&&k<maxn) { 69 MAX=tmp;maxn=k; 70 } 71 } 72 most[i][j]=MAX;mostn[i][j]=maxn; 73 } 74 } 75 int pre=0; 76 while(m--) { 77 int x,y; 78 scanf("%d%d",&x,&y); 79 x=(x+pre-1)%n+1; 80 y=(y+pre-1)%n+1; 81 if(x>y) swap(x,y); 82 if(pos[x]==pos[y]) { 83 int MAX=0,maxn; 84 for(int i=x;i<=y;i++) { 85 cou[a[i]]++; 86 int tmp=cou[a[i]]; 87 if(MAX<tmp||MAX==tmp&&a[i]<maxn) { 88 MAX=tmp;maxn=a[i]; 89 } 90 } 91 for(int i=x;i<=y;i++) { 92 cou[a[i]]--; 93 } 94 pre=b[maxn]; 95 printf("%d\n",pre); 96 }else { 97 int MAX=0,maxn; 98 for(int i=x;i<=r[pos[x]];i++) { 99 num[a[i]][pos[x]+1][pos[y]-1]++; 100 int tmp=num[a[i]][pos[x]+1][pos[y]-1]; 101 if(MAX<tmp||MAX==tmp&&a[i]<maxn) { 102 MAX=tmp;maxn=a[i]; 103 } 104 } 105 for(int i=l[pos[y]];i<=y;i++) { 106 num[a[i]][pos[x]+1][pos[y]-1]++; 107 int tmp=num[a[i]][pos[x]+1][pos[y]-1]; 108 if(MAX<tmp||MAX==tmp&&a[i]<maxn) { 109 MAX=tmp;maxn=a[i]; 110 } 111 } 112 for(int i=x;i<=r[pos[x]];i++) { 113 num[a[i]][pos[x]+1][pos[y]-1]--; 114 } 115 for(int i=l[pos[y]];i<=y;i++) { 116 num[a[i]][pos[x]+1][pos[y]-1]--; 117 } 118 int tmp=most[pos[x]+1][pos[y]-1]; 119 if(tmp<MAX||tmp==MAX&&maxn<mostn[pos[x]+1][pos[y]-1]) { 120 pre=b[maxn]; 121 printf("%d\n",pre); 122 }else { 123 pre=b[mostn[pos[x]+1][pos[y]-1]]; 124 printf("%d\n",pre); 125 } 126 } 127 } 128 return 0; 129 }
标签:分块,int,AcWing249,40,a2,初探,include,蒲公英 来源: https://www.cnblogs.com/liaxiaoquan/p/12513332.html