Codeforces 题目传送门 & 洛谷题目传送门

震惊!我竟然独立切掉了这道 *3100 的题!

虽然此题难度的确虚高,感觉真实评分也就 2800~2900 罢。但感觉还是挺有成就感的(

注意到题目中所询问的那坨东西基于每个数在区间中出现的次数,因此此题必不可少的一个步骤就是求出每个数的出现次数 \(cnt_x\),这个可以用带修莫队在 \(n^{5/3}\) 的时间内求出,这里就不再赘述了。

接下来考虑怎样计算答案,这也是本题的难点所在。我们将所有 \([l,r]\) 中出现次数非零的数的出现次数从小到大排序,设为 \(x_1,x_2,\cdots,x_m\),显然我们选择的数在 \(x\) 序列中一定是一段连续的区间 \(x_i,x_{i+1},\cdots,x_{i+k-1}\),故答案为 \(\min\limits_{i=1}^{m-k+1}x_{i+k-1}-x_i\)。

暴力排序求解显然是不行的,但是注意到 \(x\) 数组有一个非常重要的性质,就是 \(\sum\limits_{i=1}^mx_i=r-l+1\le n\),我们不妨设一个阈值 \(B\),我们考虑以下两个暴力:

  • 对于 \(x_{i+k-1}\le B\) 的 \(i\),我们开一个桶 \(cnt\_cnt_i\) 表示 \(\sum[x_j=i]\),也就是 \(x_j=i\) 的个数,然后枚举 \(x_i\),用 two pointers 找出最小的 \(r\) 使得 \(\sum\limits_{j=i}^rcnt\_cnt_j\ge k\) 并用 \(r-i\) 更新答案。
  • 对于 \(x_{i+k-1}>B\) 的 \(i\),注意到这样的 \(i\) 不超过 \(\lfloor\dfrac{n}{B}\rfloor\) 个,于是我们暴力找出 \(x_i>B\) 的 \(x_i\) 并将其从小到大排序,然后直接用 \(x_{i+k-1}-x_i\) 更新答案即可。复杂度 \(\dfrac{n}{B}\log\dfrac{n}{B}\)。

用均值不等式可知 \(B=\sqrt{n\log n}\) 时复杂度最优。

还有一个小问题,就是怎样求出 \(x_{i}>B\) 的 \(x_i\),一个很显然的思路是在莫队 push/pop 的过程中维护一个 set,如果当前加入的值的 \(cnt\ge B\) 就压入 set,否则从 set 中删除当前值,不过这样会使带修莫队的复杂度变为 \(n^{5/3}\log n\),无法通过。注意到如果 \(i\) 满足 \(i\) 从始至终在序列中出现的次数 \(<B\),那么它一定不可能出现在这个 set 中,故考虑预处理所有存在某个时刻在序列中出现次数 \(>B\) 的 \(i\)——这样的 \(i\) 必定不会超过 \(\dfrac{n}{B}\),然后每次询问时暴力在这样的 \(i\) 中查找出现次数 \(>B\) 的值,这样就能保证复杂度了。

时间复杂度 \(n^{5/3}+n\sqrt{n\log n}\)

还有一点是回滚莫队时间轴那一维是先更新再移动指针,我因此 WA 了好几发……

这个莫队板子题能放到 edu 的 G 就 nm 离谱

#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;
typedef unsigned int u32;
typedef unsigned long long u64;
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=1e5;
const int BLK_2_3=2000;
const int BLK_1_2=316;
const int INF=0x3f3f3f3f;
int n,qu,qk=0,a[MAXN+5],tot_cnt[MAXN+5],cnt[MAXN+5],cnt_cnt[MAXN+5];
int blk_cnt,L[MAXN+5],R[MAXN+5],bel[MAXN+5];
struct chg{int x,pre,cur;} c[MAXN+5];
vector<int> tot;
void push(int x){cnt_cnt[cnt[x]]--;cnt[x]++;cnt_cnt[cnt[x]]++;}
void pop(int x){cnt_cnt[cnt[x]]--;cnt[x]--;cnt_cnt[cnt[x]]++;}
struct query{
int l,r,k,id;
bool operator <(const query &rhs){
if(bel[l]!=bel[rhs.l]) return l<rhs.l;
else if(bel[r]!=bel[rhs.r]) return r<rhs.r;
return id<rhs.id;
}
} q[MAXN+5];
int ans[MAXN+5];
int deal(int k){
vector<int> over;int ret=INF;
for(int i=0;i<tot.size();i++) if(cnt[tot[i]]>BLK_1_2) over.pb(cnt[tot[i]]);
sort(over.begin(),over.end());
for(int l=1,r=1,sum=0;l<=BLK_1_2;l++){
while(r<=BLK_1_2&&sum<k) sum+=cnt_cnt[r],r++;
if(sum<k){
int need=k-sum;
if(need<=over.size()) chkmin(ret,over[need-1]-l);
} else chkmin(ret,r-l-1);
sum-=cnt_cnt[l];
}
for(int i=0;i+k-1<over.size();i++) chkmin(ret,over[i+k-1]-over[i]);
return ret;
}
int main(){
scanf("%d%d",&n,&qu);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),tot_cnt[a[i]]++;
blk_cnt=(n-1)/BLK_2_3+1;
for(int i=1;i<=blk_cnt;i++){
L[i]=(i-1)*BLK_2_3+1;R[i]=min(i*BLK_2_3,n);
for(int j=L[i];j<=R[i];j++) bel[j]=i;
}
for(int i=1;i<=qu;i++){
int opt;scanf("%d",&opt);
if(opt==1){
qk++;scanf("%d%d%d",&q[qk].l,&q[qk].r,&q[qk].k);
q[qk].id=i;
} else {
scanf("%d%d",&c[i].x,&c[i].cur);
c[i].pre=a[c[i].x];a[c[i].x]=c[i].cur;
tot_cnt[c[i].cur]++;
}
} sort(q+1,q+qk+1);int cl=1,cr=0,ct=qu;
memset(ans,-1,sizeof(ans));
for(int i=1;i<=MAXN;i++) if(tot_cnt[i]>BLK_1_2) tot.pb(i);
for(int i=1;i<=qk;i++){
while(cr<q[i].r) push(a[++cr]);
while(cl>q[i].l) push(a[--cl]);
while(cr>q[i].r) pop(a[cr--]);
while(cl<q[i].l) pop(a[cl++]);
while(ct<q[i].id){
if(c[ct].x){
if(q[i].l<=c[ct].x&&c[ct].x<=q[i].r) pop(c[ct].pre);
a[c[ct].x]=c[ct].cur;
if(q[i].l<=c[ct].x&&c[ct].x<=q[i].r) push(c[ct].cur);
} ct++;
}
while(ct>q[i].id){
if(c[ct].x){
if(q[i].l<=c[ct].x&&c[ct].x<=q[i].r) pop(c[ct].cur);
a[c[ct].x]=c[ct].pre;
if(q[i].l<=c[ct].x&&c[ct].x<=q[i].r) push(c[ct].pre);
} ct--;
} ans[q[i].id]=deal(q[i].k);
}
for(int i=1;i<=qu;i++) if(~ans[i]) printf("%d\n",(ans[i]^INF)?ans[i]:-1);
return 0;
}
/*
12 11
2 1 1 2 1 1 3 2 1 1 3 3
1 2 10 3
1 2 11 3
2 7 2
1 3 9 2
1 1 12 1
1 1 12 4
2 12 4
1 1 12 4
2 1 5
1 3 12 2
1 1 4 3
*/
/*
10 2
1 2 2 1 1 3 1 1 3 1
1 3 8 2
1 3 8 3
*/

Codeforces 1476G - Minimum Difference(带修莫队+根号平衡)的更多相关文章

  1. 【BZOJ-3052】糖果公园 树上带修莫队算法

    3052: [wc2013]糖果公园 Time Limit: 200 Sec  Memory Limit: 512 MBSubmit: 883  Solved: 419[Submit][Status] ...

  2. 「洛谷1903」「BZOJ2120」「国家集训队」数颜色【带修莫队,树套树】

    题目链接 [BZOJ传送门] [洛谷传送门] 题目大意 单点修改,区间查询有多少种数字. 解法1--树套树 可以直接暴力树套树,我比较懒,不想写. 稍微口胡一下,可以直接来一个树状数组套主席树,也就是 ...

  3. BZOJ2120 数颜色 莫队 带修莫队

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ2120.html 题目传送门 - BZOJ2120 题意 给定一个长度为 $n$ 的序列 $a$ ,有 ...

  4. BZOJ3052/UOJ#58 [wc2013]糖果公园 莫队 带修莫队 树上莫队

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ3052.html 题目传送门 - BZOJ3052 题目传送门 - UOJ#58 题意 给定一棵树,有 ...

  5. UVA 12345 Dynamic len(带修莫队)

    Dynamic len [题目链接]Dynamic len [题目类型]带修莫队 &题解: 莫队可以单点更改,只要再多加一维,代表查询次数,排序的时候3个关键字. 之后循环离线的时候,先暴力时 ...

  6. bzoj 2120 数颜色 (带修莫队)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2120 题意:两种操作:Q 询问区间  l - r  内颜色的种类 ,R 单点修改 思路 ...

  7. BZOJ 4129 Haruna’s Breakfast (分块 + 带修莫队)

    4129: Haruna’s Breakfast Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 835  Solved: 409[Submit][St ...

  8. BZOJ 2120 数颜色 (带修莫队)

    2120: 数颜色 Time Limit: 6 Sec  Memory Limit: 259 MBSubmit: 6367  Solved: 2537[Submit][Status][Discuss] ...

  9. BZOJ3052: [wc2013]糖果公园【树上带修莫队】

    Description Input Output Sample Input Sample Input Sample Output 84 131 27 84 HINT 思路 非常模板的树上带修莫队 真的 ...

随机推荐

  1. 解决更新页面版本后用户需CTRL+F5强刷才能应用最新页面

    设置文件永远不从缓存读取 第一步:在html文件设置文件不缓存 <!DOCTYPE html> <html lang="en" class="theme ...

  2. 短短 29 天,应对高峰 100W+ 访问,看浙大如何交出满分答卷

    疫情期间"停课不停教,停课不停学",线上开课第一天,浙江大学网上开课平台访问量即突破100 万次,访客数3万余人,最高峰达 1.1万人同时在线,发起课程直播2000余场,然而系统却 ...

  3. BUAA2020软工作业(四)——结对项目

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目作业 我在这个课程的目标是 进一步提高自己的编码能力,工程能力,团队协作能力 这个作业在哪 ...

  4. 如何理解Stand SPI Dual SPI 和Quad SPI??

    1.首先看一下接口 Standard SPI: CLK, /CS, DI, DO, /WP, /Hold Dual SPI: CLK, /CS, IO0, IO1, /WP, /Hold Quad S ...

  5. Python展示文件下载进度条

    前言 大家在用Python写一些小程序的时候,经常都会用到文件下载,对于一些较小的文件,大家可能不太在乎文件的下载进度,因为一会就下载完毕了. 但是当文件较大,比如下载chromedriver的时候, ...

  6. 【lwip】04-内存管理

    目录 前言 4. 内存管理 4.1 内存分配策略 4.1.1 固定大小的内存块 4.1.2 可变大小分配 4.2 动态内存池(pool) 4.2.1 介绍 4.2.2 内存池的预处理 4.2.3 内存 ...

  7. 使用jax加速Hamming Distance的计算

    技术背景 一般认为Jax是谷歌为了取代TensorFlow而推出的一款全新的端到端可微的框架,但是Jax同时也集成了绝大部分的numpy函数,这就使得我们可以更加简便的从numpy的计算习惯中切换到G ...

  8. 区块链开发学习第三章:私有链上部署helloBlockchain简单合约

    前面讲了部署私有链以及新增账户,现在进行到了部署合约了,此操作真是踩了无数无数无数的坑,到写文章为止确实是已经部署好了,但是还有些坑是还没有解决的! 一.Solidity编译器 开始的时候用的http ...

  9. centos yum更换阿里镜像

    #1.如果没有wget命令,则需要执行下面命令进行安装.为保险期间,先执行下面命令. yum install wget #2.备份原镜像源,以免出错后可以恢复. mv /etc/yum.repos.d ...

  10. mybatis之结果集的映射方式

    查询的几种情况 // 1)查询单行数据返回单个对象 public Employee getEmployeeById(Integer id ); // 2) 查询多行数据返回对象的集合 public L ...