【bzoj2724】[Violet 6]蒲公英 分块+STL-vector

题目描述

输入

修正一下

l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1

输出

样例输入

6 3
1 2 3 2 1 2
1 5
3 6
1 5

样例输出

1
2
1



题解

分块+STL-vector

一个显而易见的结论:区间众数一定是一段连续的块的众数或块外的数,证明略(逃

先把数据离散化,然后分块预处理出f[i][j],表示从块i到块j的众数位置。具体实现的话直接开个桶存一下就好了。

然后考虑询问,整块的直接拿出来求一下出现次数,块外的单独拿出来求一下出现次数,只要求$2\sqrt n+1$次。

现在只要想出怎样求出来出现次数即可。一个简单地方法是:对于每个数开一个vector存一下出现位置,然后在vector上二分查找出现位置。

总时间复杂度为$O(n\sqrt n\log n)$,常数有点大...

#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#define N 50010
#define bl(x) (x - 1) / si
using namespace std;
vector<int> v[N];
int a[N] , c[N] , cnt[N] , f[250][250] , ref[N];
int query(int p , int l , int r)
{
    return upper_bound(v[p].begin() , v[p].end() , r) - lower_bound(v[p].begin() , v[p].end() , l);
}
int main()
{
    int n , m , si , i , j , t , maxn , x , y , ans , last = 0;
    scanf("%d%d" , &n , &m) , si = (int)sqrt(n);
    for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , c[i] = a[i];
    sort(c + 1 , c + n + 1);
    for(i = 1 ; i <= n ; i ++ ) t = a[i] , a[i] = lower_bound(c + 1 , c + n + 1 , a[i]) - c , v[a[i]].push_back(i) , ref[a[i]] = t;
    for(i = 0 ; i <= (n - 1) / si ; i ++ )
    {
        memset(cnt , 0 , sizeof(cnt)) , maxn = 0;
        for(j = i * si + 1 ; j <= n ; j ++ )
        {
            cnt[a[j]] ++ ;
            if(cnt[a[j]] > maxn || (cnt[a[j]] == maxn && a[j] < t)) maxn = cnt[a[j]] , t = a[j];
            if(j % si == 0) f[i][bl(j)] = t;
        }
    }
    while(m -- )
    {
        scanf("%d%d" , &x , &y) , x = (x + last - 1) % n + 1 , y = (y + last - 1) % n + 1 , maxn = 0;
        if(x > y) swap(x , y);
        if(bl(y) - bl(x) < 2)
        {
            for(i = x ; i <= y ; i ++ )
                if((t = query(a[i] , x , y)) > maxn || (t == maxn && a[i] < ans))
                    maxn = t , ans = a[i];
        }
        else
        {
            for(i = x ; i <= (bl(x) + 1) * si ; i ++ )
                if((t = query(a[i] , x , y)) > maxn || (t == maxn && a[i] < ans))
                    maxn = t , ans = a[i];
            if((t = query(f[bl(x) + 1][bl(y) - 1] , x , y)) > maxn || (t == maxn && f[bl(x) + 1][bl(y) - 1] < ans))
                maxn = t , ans = f[bl(x) + 1][bl(y) - 1];
            for(i = bl(y) * si + 1 ; i <= y ; i ++ )
                if((t = query(a[i] , x , y)) > maxn || (t == maxn && a[i] < ans))
                    maxn = t , ans = a[i];
        }
        printf("%d\n" , last = ref[ans]);
    }
    return 0;
}
时间: 2024-10-11 11:25:44

【bzoj2724】[Violet 6]蒲公英 分块+STL-vector的相关文章

【BZOJ2724】[Violet 6]蒲公英 分块+二分

[BZOJ2724][Violet 6]蒲公英 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Output 1 2 1 HINT 修正下: n <= 40000, m <= 50000 题解:分块还是练脑子啊~ 结论:一个区间的众数要么是区间中一个块的众数,要么是块外的任意

BZOJ2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 795  Solved: 248[Submit][Status] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input Sample Output HINT 修正下: n <= 40000, m <= 50000 S

bzoj2724: [Violet 6]蒲公英(分块)

传送门 md调了一个晚上最后发现竟然是空间开小了……明明算出来够的…… 讲真其实我以前不太瞧得起分块,觉得这种基于暴力的数据结构一点美感都没有.然而今天做了这道分块的题才发现分块的暴力之美(如果我空间没有开小就更美了) 我们先将整个数组分块,设块的大小为$T$ 我们先预处理出所有以块边界为端点的区间的答案,即$ans[L][R]$代表着第$L$块到第$R$块的序列所代表的答案.这个可以$O(n*n/T)$预处理 然后我们先将所有的数给离散化,然后对每一个值都开一个vector,记录这个值在数组中

【分块】bzoj2724 [Violet 6]蒲公英

分块,离散化,预处理出: ①前i块中x出现的次数(差分): ②第i块到第j块中的众数是谁,出现了多少次. 询问的时候,对于整块的部分直接获得答案:对于零散的部分,暴力统计每个数出现的次数,加上差分的结果,尝试更新ans. 1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 int n,m,sum,sz,n

bzoj2724: [Violet 6]蒲公英(离散化+分块)

我好弱啊..这题调了2天QwQ 题目大意:给定一个长度为n(n<=40000)的序列,m(m<=50000)次询问l~r之间出现次数最多的数.(区间众数) 这题如果用主席树就可以不用处理一堆前缀和..蓝鹅我不会~T_T~. 把序列n分成sqrt(n)块,先把所有数离散化,预处理出poi[i][j]表示第i块到第j块的众数(即出现次数最多的数). 询问有两种情况: 第一种情况是l~r在某个块中,那么直接扫一遍求出众数,效率O(sqrt(n)). 第二种情况是l~r在多个块中,l在x块,r在y块,

【BZOJ 2724】 2724: [Violet 6]蒲公英 (区间众数不带修改版本)

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1908  Solved: 678 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Output 1 2 1 HINT 修正下: n <= 4

BZOJ 2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1633  Solved: 563[Submit][Status][Discuss] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Outp

【BZOJ 2724】 [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MB Submit: 970  Solved: 319 [Submit][Status][Discuss] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Out

「Violet」蒲公英

「Violet」蒲公英 传送门 区间众数,强制在线. 分块经典题. 像这题一样预处理,然后就直接爆搞,复杂度 \(O(n \sqrt n)\) 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".ou