分块 (查找区间最小众数

题目链接https://loj.ac/problem/6285

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<cstdio>
  6 #include<string>
  7 #include<vector>
  8 #include<cmath>
  9 #include<iomanip>
 10 #include<bitset>
 11 #include<queue>
 12 #include<stack>
 13 #include<map>
 14 #include<set>
 15 #include<list>
 16 using namespace std;
 17 const int maxn = 1e5 + 10;
 18 int n, t, l, r, id, ans;
 19 int pos[maxn], val[maxn], m[3500][3500], a[maxn], sum[maxn];
 20 map<int, int> ls;
 21 vector<int> v[maxn];
 22 
 23 inline int read()
 24 {
 25     char ch = getchar(); int k = 0, f = 1;
 26     while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
 27     while(ch >= '0' && ch <= '9') {k = (k << 1) + (k << 3) + ch - '0'; ch = getchar();}
 28     return k * f;
 29 }
 30 
 31 inline int findy(int a, int l, int r)
 32 {
 33     return upper_bound(v[a].begin(), v[a].end(), r) - lower_bound(v[a].begin(), v[a].end(), l); // 第一个大于r的地址减去第一个大于等于l的地址可得区间内出现次数
 34 }
 35 
 36 inline void deal(int x)
 37 {
 38     int maxx = 0, mx = 0;
 39     memset(sum, 0, sizeof(sum));
 40     for(int i = (x - 1) * t + 1; i <= n; ++i)
 41     {
 42         sum[a[i]]++;
 43         if(sum[a[i]] > maxx || (sum[a[i]] == maxx) && val[mx] > val[a[i]])
 44             mx = a[i], maxx = sum[a[i]];
 45         m[x][pos[i]] = mx; // 记录第几块左边界到第几块右边界的最小众数
 46     }
 47 }
 48 
 49 int query(int l,int r)
 50 {
 51     int cnt, mx=0, maxx;
 52     mx = m[pos[l] + 1][pos[r] - 1];
 53     maxx = findy(mx, l, r);
 54 
 55     if(pos[l]==pos[r])
 56     {
 57         for(int i = l; i <= r; ++i)
 58         {
 59             cnt = findy(a[i], l, r);
 60             if(cnt > maxx || ( cnt == maxx && val[mx] > val[a[i]])) mx = a[i], maxx = cnt;
 61         }
 62     }
 63 
 64     else
 65     {
 66         for(int i = l; i <= pos[l]*t; ++i)
 67         {
 68             cnt = findy(a[i], l, r);
 69             if(cnt > maxx || ( cnt == maxx && val[mx] > val[a[i]])) mx = a[i], maxx = cnt;
 70         }
 71 
 72         for(int i = (pos[r] - 1) * t + 1; i <= r; ++i)
 73         {
 74             cnt = findy(a[i], l, r);
 75             if(cnt > maxx || (cnt == maxx && val[mx] > val[a[i]])) mx = a[i], maxx = cnt;
 76         }
 77     }
 78     return mx;
 79 }
 80 
 81 int main()
 82 {
 83     n = read(); t = 100; // t取50 100 200 可以很好解决数据小但是分块多的情况不然可能会tle
 84 
 85     for(int i = 1; i <= n; ++i) // 进行离散化
 86     {
 87         a[i] = read();
 88         if(!ls[a[i]])
 89         {
 90             ls[a[i]] = ++id; // ls通过原值找现值
 91             val[id] = a[i];  // val通过现值找原值
 92         }
 93         a[i] = ls[a[i]];
 94         v[a[i]].push_back(i); // 将相同值的序号存进vector,此时寻找某值在某区间内的次数就很好找
 95     }
 96 
 97     for(int i = 1; i <= n; ++i) pos[i] = (i - 1) / t + 1;
 98     for(int i = 1; i <= pos[n]; ++i) deal(i);
 99 
100     for(int i = 1; i <= n; ++i)
101     {
102         l = read(), r = read();
103         if(l > r) swap(l, r);
104         printf("%d\n", val[query(l, r)]);
105     }
106     return 0;
107 }

 分块入门到此就结束了 (撒花撒花

莫队的版本等我会了再回来补。

posted @ 2020-08-08 21:51  YanMingA  阅读(156)  评论(0编辑  收藏  举报