zoukankan      html  css  js  c++  java
  • 分块 (查找区间最小众数

    题目链接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
    ", val[query(l, r)]);
    105     }
    106     return 0;
    107 }

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

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

  • 相关阅读:
    explicit
    boolalpha 和 noboolalpha
    C++ 头文件一览
    C++ I/O库总结
    Error:collect2:ld returned 1 exit status (总结)
    常用目录的作用
    硬盘分区与硬软链接
    POJ3694 Network(Tarjan双联通分图 LCA 桥)
    2016"百度之星"
    2016"百度之星"
  • 原文地址:https://www.cnblogs.com/a1484755603/p/13460542.html
Copyright © 2011-2022 走看看