luogu P4168 [Violet]蒲公英

嘟嘟嘟

分块经典题竟然是一道黑题……

分块求区间众数的大体思想是对于询问区间[L, R],预处理出这中间的整块的众数,然后统计两边零散的数在[L, R]中出现的次数,最后取出现次数最多且最小的数。

因此需要一个sum[i][j]表示前 i 块中数字 j 出现的次数,ans[i][j]表示块 i 到 j 的众数。预处理sum用前缀和的思想,O(n√n)可完成。预处理ans就是枚举左端点是第几个块,然后每一次从这个块的左端点O(n)扫一遍,复杂度也是O(n√n)。

查询的时候,整块的众数即其个数分别是pos = ans[l + 1][r - 1],Max = sum[r - 1][pos] - sum[l][pos]。然后零散的数我们单独开一个数组记录一下,同时记录他在零三部分出现的次数num[i],这样这个数在[L, R]中出现的次数就是sum[r - 1][x] - sum[l][x] + num[x]。最后比较取大。

本题ai较大,所以要离散化,这并不影响众数。

采纳lba大佬的意见,为了避免重复运算从而降低常数,多开了三个数组分别记录每一个数属于哪个块,以及每一个块的左右端点是多少。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define enter puts("") 
 13 #define space putchar(' ')
 14 #define Mem(a, x) memset(a, x, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const int maxn = 4e4 + 5;
 21 inline ll read()
 22 {
 23     ll ans = 0;
 24     char ch = getchar(), last = ' ';
 25     while(!isdigit(ch)) {last = ch; ch = getchar();}
 26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
 27     if(last == '-') ans = -ans;
 28     return ans;
 29 }
 30 inline void write(ll x)
 31 {
 32     if(x < 0) x = -x, putchar('-');
 33     if(x >= 10) write(x / 10);
 34     putchar(x % 10 + '0');
 35 }
 36 
 37 int n, m, a[maxn], t[maxn];
 38 
 39 int S, Cnt = 0, blo[maxn], lb[210], rb[210];
 40 int sum[210][maxn], ans[210][210], num[maxn];
 41 void init()
 42 {
 43     S = sqrt(n);
 44     Cnt = (n % S) ? n / S : n / S + 1;
 45     for(int i = 1; i <= Cnt; ++i) lb[i] = (i - 1) * S, rb[i] = i * S - 1;
 46     rb[Cnt] = n;   //一定要有,否则会gg
 47     for(int i = 1, j = 1; i <= n; ++i) blo[i] = j, j += (i == rb[j]);
 48     for(int i = 1; i <= Cnt; ++i)
 49     {
 50         for(int j = 1; j <= n; ++j) sum[i][j] += sum[i - 1][j];
 51         for(int j = lb[i]; j <= rb[i]; ++j) sum[i][a[j]]++;
 52     }
 53     for(int i = 1; i <= Cnt; ++i)
 54     {
 55         Mem(num, 0); int Max = -1, pos;
 56         for(int j = lb[i], k = i; j <= n; ++j)
 57         {
 58             if(++num[a[j]] > Max) Max = num[a[j]], pos = a[j];
 59             if(num[a[j]] == Max && a[j] < pos) pos = a[j];
 60             if(j == rb[k]) ans[i][k] = pos, k++;
 61         }
 62     }
 63 }
 64 int temp[210], cp = 0;
 65 int query(int L, int R)
 66 {
 67     Mem(num, 0); cp = 0;
 68     int l = blo[L], r = blo[R];
 69     int Max = -1, pos;
 70     if(l == r)
 71     {
 72         for(int i = L; i <= R; ++i)
 73         {
 74             if(++num[a[i]] > Max) Max = num[a[i]], pos = a[i];
 75             if(num[a[i]] == Max && a[i] < pos) pos = a[i];
 76         }
 77         return pos;
 78     }
 79     pos = ans[l + 1][r - 1]; Max = sum[r - 1][pos] - sum[l][pos];
 80     for(int i = L; i <= rb[l]; ++i)
 81     {
 82         if(!num[a[i]]) temp[++cp] = a[i];
 83         num[a[i]]++;
 84     }
 85     for(int i = lb[r]; i <= R; ++i)
 86     {
 87         if(!num[a[i]]) temp[++cp] = a[i];
 88         num[a[i]]++;
 89     }
 90     for(int i = 1; i <= cp; ++i)
 91     {
 92         int tp = sum[r - 1][temp[i]] - sum[l][temp[i]] + num[temp[i]];
 93         if(tp > Max) Max = tp, pos = temp[i];
 94         if(tp == Max && temp[i] < pos) pos = temp[i];
 95     }
 96     return pos;
 97 }
 98 
 99 int Ans = 0;
100     
101 int main()
102 {
103     n = read(); m = read();
104     for(int i = 1; i <= n; ++i) t[i] = a[i] = read();
105     sort(t + 1, t + n + 1);
106     int _n = unique(t + 1, t + n + 1) - t - 1;
107     for(int i = 1; i <= n; ++i)     
108         a[i] = lower_bound(t + 1, t + _n + 1, a[i]) - t;
109     init();
110     for(int i = 1; i <= m; ++i)
111     {
112         int L = read(), R = read();
113         L = (L + Ans - 1) % n + 1; R = (R + Ans - 1) % n + 1;
114         if(L > R) swap(L, R);
115         Ans = t[query(L, R)];   //别忘了输出原数
116         write(Ans), enter;
117     }
118     return 0;
119 }
View Code
原文地址:https://www.cnblogs.com/mrclr/p/9868510.html