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. 机器学习:SVM

    SVM 前言:支持向量机(Support Vector Machine, SVM),作为最富盛名的机器学习算法之一,其本身是一个二元分类算法,为了更好的了解SVM,首先需要一些前提知识,例如:梯度下降 ...

  2. [技术博客] 软工-Ruby on Rails 后端开发总结分享

    [技术博客] 软工-Ruby on Rails 后端开发总结分享 在这次软件编写中,我们的后端使用了Ruby on Rails (RoR)框架. Rails框架是用Ruby编写的.这意味着当我们为Ru ...

  3. VS2019、Qt5.12及QGis3.16开发常见问题汇总

    在C++.Qt软件开发过程中,常常遇到一些编译错误或警告:本文将VS2019.Qt5.12.10和QGis3.16.10的二次开发过程常见的问题做了整理,供大家参考,也便于日后查阅.该内容分为四部分: ...

  4. 疯狂Java基础Day1

    --每过一遍基础,都是一次提升! 太多遗忘了,慢慢补... 推一个Java学习教程--->b站搜:狂神说Java系列(排序完毕) 推荐原因:讲的不错,会涉及到底层,也会讲讲面试. 一.注释 主要 ...

  5. 《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)

    1.简介 前边几篇文章是宏哥自己在本地弄了一个单选和多选的demo,然后又找了网上相关联的例子给小伙伴或童鞋们演示了一下如何自动化测试,这一篇宏哥在网上找了一个问卷调查,给小伙伴或童鞋们来演示一下.上 ...

  6. 求1+2+3...+n 牛客网 剑指Offer

    求1+2+3...+n 牛客网 剑指Offer 题目描述 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). ...

  7. Tcpdump 常用命令、参数记录

    一.介绍 一个关于Centos  Tcpdump 的个人工作总结. 二.参数介绍: 1. -i:   指定要进行抓包的网卡 2.-s0 :表示每个报文的大小是接收到的指定大小,如果没有这个选项,则超过 ...

  8. 如何系统学习C 语言(中)之 指针篇

    谈到指针,我们可能会想到钟表上的指针,但这里的指针不是现实生活中看得见摸得着的钟表上的指针,c 语言中的指针只存在于逻辑思维中,物理上并不存在. 同时,指针也是C 语言中最精华的部分,通过灵活地运用指 ...

  9. [命令行]Mysql 导入 excel 文件

    将 excel 表格中的数据批量导入数据库中 将要导入的表删除字段名,只留下要导入的数据. 将文件另存为 *.csv格式,可以用记事本打开(实际上就是标准的逗号分隔的数据 进入mysql,输入命令,打 ...

  10. Redis网络库源码分析(1)之介绍篇

    一.前言 Redis网络库是一个单线程EPOLL模型的网络库,和Memcached使用的libevent相比,它没有那么庞大,代码一共2000多行,因此比较容易分析.其实网上已经有非常多有关这个网络库 ...