[Luogu]5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III[分块]

题意

长为 \(n\) 的序列,询问区间众数,强制在线。

\(n\leq 5\times 10^5\).

分析

  • 考虑分块,暴力统计出整块到整块之间的众数次数。
  • 然后答案还可能出现在两边的两个独立的块中,开 \(vector\) 记录每种数字出现的位置集合,然后暴力判断两边两个块中的元素出现的次数。发现并不需要知道具体在 \([l,r]\) 内出现了多少次,而只需要知道 \([l,r]\) 中是否有 \(ans+1\)个该种颜色。
  • 总时间复杂度为 \(O(n\sqrt n)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].lst,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
    return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=5e5 + 7,M=720;
int n,m,len,sz,tp;
int V[N],bl[N],a[N],p[N],cnt[N],f[M][M],st[N],vc[N];
int L(int x){return (x-1)*sz+1;}
int R(int x){return min(n,x*sz);}
vector<int>pos[N];
int solve(int l,int r){
    int res=0;
    if(bl[l]==bl[r]){
        for(int i=l;i<=r;++i){
            st[++tp]=a[i];
            Max(res,++cnt[a[i]]);
        }
        for(;tp;--tp) cnt[st[tp]]=0;
        return res;
    }
    res=f[bl[l]+1][bl[r]-1];
    for(int i=R(bl[l]);i>=l;--i){
        int x=p[i],y=x+res;
        if(y<vc[a[i]]&&pos[a[i]][y]<=r) ++res;
    }
    for(int i=L(bl[r]);i<=r;++i){
        int y=p[i],x=y-res;
        if(x>=0&&pos[a[i]][x]>=l) ++res;
    }
    return res;
}
int main(){
    n=gi(),m=gi();sz=sqrt(n);
    rep(i,1,n) a[i]=gi(),bl[i]=(i-1)/sz+1,V[i]=a[i];

    sort(V+1,V+1+n);
    len=unique(V+1,V+1+n)-V-1;
    rep(i,1,n) a[i]=lower_bound(V+1,V+1+len,a[i])-V,pos[a[i]].pb(i),p[i]=pos[a[i]].size()-1;
    rep(i,1,len) vc[i]=pos[i].size();
    for(int p=1;p<=bl[n];++p){
        int tmp=0,tp=0;
        for(int i=L(p);i<=n;++i){
            Max(tmp,++cnt[a[i]]);
            st[++tp]=a[i];
            if(i%sz==0) f[p][bl[i]]=tmp;
        }
        for(;tp;--tp) cnt[st[tp]]=0;
    }
    int lastans=0;
    while(m--){
        int l=gi()^lastans,r=gi()^lastans;
        if(l>r) swap(l,r);
        printf("%d\n",lastans=solve(l,r));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/yqgAKIOI/p/10010650.html

时间: 2024-10-09 19:50:36

[Luogu]5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III[分块]的相关文章

P5048 [[Ynoi2019模拟赛]Yuno loves sqrt technology III]

为什么我感觉这题难度虚高啊-- 区间众数的出现次数- 计算器算一下 \(\sqrt 500000 = 708\) 然后我们发现这题的突破口? 考虑分块出来[L,R]块的众数出现个数 用 \(\texttt{mx[L][R]}\) 维护就可以了 每次考虑一个L- 然后R指针一直向右移不断的更新到N 这样子做的复杂度因为最多有 \(\sqrt n\) 个块 所以复杂度大概是 \(n\sqrt n\) 实际上还少一点- 然后整块的想好了--单独的怎么处理? 分类讨论 1 \(\texttt{L}\)和

NOI2016模拟赛Zbox loves stack

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 #define PI pair<int,int> 8 #define fi first 9 #define se second 10 #define mp(a,b) make_p

【BZOJ】【2741】【FOTILE模拟赛】L

可持久化Trie+分块 神题……Orz zyf & lyd 首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问[某个区间中最大的区间异或和]改变成[某个区间中 max(两个数的异或和)] 要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了:然而我们并不能. 一个常见的折中方案:分块! 这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值. 我们不预处理所有的左端点,我

bzoj2741: 【FOTILE模拟赛】L

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 2679  Solved: 766[Submit][Status][Discuss] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一

noip模拟赛 街灯

分析:对于前30%的数据直接暴力模拟即可,对于另外30%的数据,因为每次的p是一样的,所以可以用莫队来维护,先离散化一下,再用一个桶统计次数. 100%的做法和之前做过的一道模拟赛题很像,当模数很小的时候分块,否则就暴力修改.其实看到区间操作第一感觉是线段树,但是线段树并不能维护这个,分块维护的信息多一些,所以分块.在模数较小的时候记录一下第i个块,模p等于v的有多少个,即g[i][p][v],利用前缀和统计1~i个块的个数.在模数较大的时候因为只有v,v+p,v+2p对答案有影响,所以记录第i

【前行】◇第3站◇ 国庆训练营&#183;OI制模拟赛

[第3站] 国庆训练营·OI制模拟赛Ⅰ 怀着冲刺提高组400的愿望来到这个very small but very interesting 的训练营QwQ 在北大dalao的带领下开始了第一场OI模拟赛[炸心态ヽ(*.>Д<)o゜] ? 简单总结 感觉非常爆炸…… 第一题还好,一眼看出结论题,所以开始打表……没想到只打出来了一种情况(为什么全是特殊情况),然后就凉了. 第二题就开始崩溃了.首先画图思考了大概20分钟……然后发现想不出正解,就开始想要骗分.看了看数据阶梯,发现自己好像只能做前1/3

2.23模拟赛

浪了一发普及模拟赛 题面见此 [样例输入] 4 1 1 2 1 1 1 [样例输出] 20 [数据规模和范围] 对于 30%的数据,n≤1000. 对于另外 30%的数据,bi=1. 对于 100%的数据,n≤1 000 000,bi≤1000. sol:单边记贡献,(x,y)边的贡献就是 Size[y]*(n-Size[y])*Dis[x][y],因为父亲都小于当前点,直接倒着跑一遍记Size就可以了,如果无序的话可以用拓扑 #include <bits/stdc++.h> using na

ZROI 19.08.07模拟赛

传送门 写在前面:为了保护正睿题目版权,这里不放题面,只写题解. "正睿从来没有保证,模拟赛的题目必须原创." "文案不是我写的,有问题找喵老师去."--蔡老师 A R爷再次翻车,搞出来了一道六年前的CF题. \(100pts:\) 然而不是原题也很简单,斜率优化板子,单调队列搞一下就完事了. 也可以wqs二分,复杂度可以做到\(O(m\log m)\),\(与\)p\(无关.所以R爷差点把\)p$出到\(10^5\). B 本题乱搞做法非常多,所以R爷动用了权限来

10.2模拟赛总结

10.2 模拟赛总结 T1. 数位dp: 一个非常非常非常非常显然的数位 DP \([L,R] = [1,R]-[1,L-1]\) 所以是分别求两次小于等于某个数字的方案数 \(f(i,j,k)\) 表示从低位数起的第 \(i\) 位,按照规则计算后答案为 \(j\quad (j=0,1)\) \(k\) 表示只考虑后面结尾和 \(lmt\)后面几位 的大小关系 \((k=0,1)\) 考虑第 \(i+1\) 位,算一下新构成的数字并判断下大小就可以了 注意到 \(L,R\) 数据范围特别大,需