zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    8、泛型程序设计与c++标准模板库5.函数对象
    Linux和Windows系统分区原理
    Linux命令----cd
    为什么会产生TCP/IP?
    区间 dp
    dp-划分数 (递推)
    dp-LCS(递归输出最短合串)
    dp-(LCS 基因匹配)
    位运算符
    求对数
  • 原文地址:https://www.cnblogs.com/mrclr/p/9868510.html
Copyright © 2011-2022 走看看