题面传送门

qwq 感觉跟很多年前做过的一道题思路差不多罢,结果我竟然没想起那道题?!!所以说我 wtcl/wq

首先将 \(a_i\) 离散化。

如果允许离线那显然一遍莫队就能解决,复杂度 \(n\sqrt{n}\)。

那如果强制在线怎么办呢?

既然离线都只能做到 \(n\sqrt{n}\),那在线肯定至少 \(n\sqrt{n}\) 咯

考虑将原序列分块,我们预处理处 \(mx_{i,j}\) 表示第 \(i\) 块开头到第 \(j\) 块结尾的区间中出现次数最多的值的出现次数。这个显然可以 \(n\sqrt{n}\) 求出,具体来说枚举开头的块 \(i\) 并实时维护一个桶 \(cnt_i\),然后一遍向后扫描一遍更新答案即可。

接下来考虑怎样求出答案:

  • 如果 \(l,r\) 在同一块中那直接暴力统计答案即可,复杂度 \(\sqrt{n}\)。
  • 如果 \(l,r\) 不在同一块中,我们掏出求得的 \(mx\) 数组,先令 \(ans=mx_{bel_l+1,bel_r-1}\),也就是 \([l,r]\) 中间整块的答案。然后考虑边角元素对答案的影响。我们对每个值 \(v\) 开一个 std::vector<int> \(pos\) 维护其出现的位置,记 \(p_i\) 为 \(i\) 在 \(pos_{a_i}\) 中的位置。对于左边的边角元素 \(i\in[l,R[bel[r]]]\),如果 \(i\) 能使答案变得更优,那么 \(a_i\) 在 \([l,r]\) 中出现的次数应当大于 \(ans\),换句话说,\(pos[a[i]][p[i]+ans]\leq r\),那我们可以暴力往右移,每次答案加一,直到 \(pos[a[i]][p[i]+ans]>r\)。对于右边的边角元素也同理,不难发现边角元素最多 \(2\sqrt{n}\) 个,故 \(ans\) 最多自增 \(2\sqrt{n}\) 次,故查询复杂度 \(\sqrt{n}\)。

总复杂度 \(n\sqrt{n}\),只要常数稍微小一点即可通过本题时限。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=5e5;
const int MAX_BLK=710;
int n,qu,a[MAXN+5],key[MAXN+5],uni[MAXN+5],num;
int blk,blk_cnt,L[MAX_BLK+5],R[MAX_BLK+5],bel[MAXN+5];
int mx[MAX_BLK+5][MAX_BLK+5],cnt[MAXN+5];
vector<int> pos[MAXN+5];int p[MAXN+5];
int main(){
scanf("%d%d",&n,&qu);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),key[i]=a[i];
sort(key+1,key+n+1);key[0]=-1;
for(int i=1;i<=n;i++) if(key[i]!=key[i-1]) uni[++num]=key[i];
for(int i=1;i<=n;i++) a[i]=lower_bound(uni+1,uni+num+1,a[i])-uni;
blk=(int)pow(n,0.5);blk_cnt=(n-1)/blk+1;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*blk+1;R[i]=min(i*blk,n);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
for(int i=1;i<=blk_cnt;i++){
memset(cnt,0,sizeof(cnt));int ret=0;
for(int j=i;j<=blk_cnt;j++){
for(int k=L[j];k<=R[j];k++){
cnt[a[k]]++;chkmax(ret,cnt[a[k]]);
} mx[i][j]=ret;
}
}
for(int i=1;i<=n;i++) pos[a[i]].pb(i),p[i]=pos[a[i]].size()-1;
int ans=0;memset(cnt,0,sizeof(cnt));
while(qu--){
int l,r;scanf("%d%d",&l,&r);l^=ans;r^=ans;ans=0;
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++) cnt[a[i]]++;
for(int i=l;i<=r;i++) chkmax(ans,cnt[a[i]]);
for(int i=l;i<=r;i++) cnt[a[i]]--;
printf("%d\n",ans);
} else {
ans=mx[bel[l]+1][bel[r]-1];
for(int i=l;i<=R[bel[l]];i++){
int cur=p[i];
while(cur+ans<pos[a[i]].size()&&pos[a[i]][cur+ans]<=r)
++ans;
}
for(int i=L[bel[r]];i<=r;i++){
int cur=p[i];
while(cur-ans>=0&&pos[a[i]][cur-ans]>=l)
++ans;
}
printf("%d\n",ans);
}
}
return 0;
}
/*
10 1
1 2 3 3 2 3 3 1 1 2
4 10
*/

洛谷 P5048 - [Ynoi2019 模拟赛] Yuno loves sqrt technology III(分块)的更多相关文章

  1. [洛谷P5048][Ynoi2019模拟赛]Yuno loves sqrt technology III

    题目大意:有$n(n\leqslant5\times10^5)$个数,$m(m\leqslant5\times10^5)$个询问,每个询问问区间$[l,r]$中众数的出现次数 题解:分块,设块大小为$ ...

  2. 洛谷P5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III(分块)

    传送门 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 用蒲公英那个分块的方法做结果两天没卡过去→_→ 首先我们分块,预处理块与块之间的答案,然后每次询问的时候拆成整块和两边剩下的元素 整块的答案很简 ...

  3. Luogu P5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III 分块

    这才是真正的$N\sqrt{N}$吧$qwq$ 记录每个数$vl$出现的位置$s[vl]$,和每个数$a[i]=vl$是第几个$vl$,记为$P[i]$,然后预处理出块$[i,j]$区间的答案$f[i ...

  4. 洛谷 P5046 [Ynoi2019 模拟赛] Yuno loves sqrt technology I(分块+卡常)

    洛谷题面传送门 zszz,lxl 出的 DS 都是卡常题( 首先由于此题强制在线,因此考虑分块,我们那么待查询区间 \([l,r]\) 可以很自然地被分为三个部分: 左散块 中间的整块 右散块 那么这 ...

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

    为什么我感觉这题难度虚高啊-- 区间众数的出现次数- 计算器算一下 \(\sqrt 500000 = 708\) 然后我们发现这题的突破口? 考虑分块出来[L,R]块的众数出现个数 用 \(\text ...

  6. [Luogu5048] [Ynoi2019模拟赛]Yuno loves sqrt technology III[分块]

    题意 长为 \(n\) 的序列,询问区间众数,强制在线. \(n\leq 5\times 10^5\). 分析 考虑分块,暴力统计出整块到整块之间的众数次数. 然后答案还可能出现在两边的两个独立的块中 ...

  7. [luogu5048] [Ynoi2019模拟赛] Yuno loves sqrt technology III

    题目链接 洛谷. Solution 思路同[BZOJ2724] [Violet 6]蒲公英,只不过由于lxl过于毒瘤,我们有一些更巧妙的操作. 首先还是预处理\(f[l][r]\)表示\(l\sim ...

  8. [Ynoi2019模拟赛]Yuno loves sqrt technology III

    题目大意: 给你一个长为n的序列a,m次询问,每次查询一个区间的众数的出现次数,强制在线. 解题思路: 出题人题解 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 首先得离散化. 分块后,预处理Fi, ...

  9. [Ynoi2019模拟赛]Yuno loves sqrt technology I

    题目描述 给你一个长为n的排列,m次询问,每次查询一个区间的逆序对数,强制在线. 题解 MD不卡了..TMD一点都卡不动. 强制在线的话也没啥好一点的方法,只能分块预处理了. 对于每个块,我们设lef ...

随机推荐

  1. 无网环境安装docker之--rpm

    总体思路:找一台可以联网的linux,下载docker的RPM依赖包而不进行安装(yum localinstall),将所有依赖的rpm环境打包好,再在无网环境中解压逐一安装(rpm:  --forc ...

  2. STL模板

    目录 栈stack 队列queue 列表List 集合set 映射map 多重映射multimap 对pair 元组tuple 容器containers 算法algorithms 仿函数/函数对象fu ...

  3. Shadertoy 教程 Part 3 - 矩形和旋转

    Note: This series blog was translated from Nathan Vaughn's Shaders Language Tutorial and has been au ...

  4. objdump--反汇编查看

    转载:objdump命令_Linux objdump 命令用法详解:显示二进制文件信息 (linuxde.net) objdump命令 编程开发 objdump命令是用查看目标文件或者可执行的目标文件 ...

  5. Ubuntu鼠标变十字 不能点击

    出现这种情况,应该是bash 直接运行了python文件 系统中出现了一个import 进程. python文件中除了注释应该是import在最前边 ps -ef|grep import 可以查看系统 ...

  6. pascals-triangle-ii leetcode C++

    Given an index k, return the k th row of the Pascal's triangle. For example, given k = 3, Return[1,3 ...

  7. popStar机机对战数据生成器代码(C#)

    代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; ...

  8. 深入了解Mybatis架构设计

    架构设计 我们可以把Mybatis的功能架构分为三层: API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库.接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理. ...

  9. mysql登录后重置root密码的步骤

    mysql重置root密码. 方法一: 编辑配置文件 /etc/my.cnf ,在[mysqld]后面任意一行添加"skip-grant-tables"用来跳过密码验证 接下来我们 ...

  10. 修改linux 两种时间的方法

    1,整理了一下怎么修改linux 两种时间的方法. 硬件时间:hwclock 或者clock,设置的方法是 hwclock --set --date="05/12/2018 12:30:50 ...