编程语言
首页 > 编程语言> > 分块算法初探 AcWing249 蒲公英

分块算法初探 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