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. [技术博客]在团队中使用Pull Request来管理代码

    在团队中使用Pull Request来管理代码 前言 在参加多人共同开发项目,且选用Git作为代码托管工具的时候,我们不免会遇到分支冲突.覆盖.合并等问题.显然,因为同一个仓库是属于大家的,所以每个人 ...

  2. 百度OCR技术博客

    百度OCR工具链使用 百度OCR的API使用总体来说比较容易,主要步骤为:注册云平台并登录,选择服务并创建应用,保存API Key以及Secret Key,选择调用API. 注册登录百度云平台 首先需 ...

  3. vs2010中使用命令行参数

    使用VS2010增加命令参数的时候老是不起作用,后面经过研究发现,所要增加的命令参数是一个相对文件路径,而默认的工作目录里面没有该文件,所以就没有找到,需要修改工作目录,这样命令行参数才能够起作用.

  4. HDI PCB一阶和二阶和三阶如何区分??

      一阶板,一次压合即成,可以想像成最普通的板二阶板,两次压合,以盲埋孔的八层板为例,先做2-7层的板,压好,这时候2-7的通孔埋孔已经做好了,再加1层和8层压上去,打1-8的通孔,做成整板.三阶板就 ...

  5. Unity——射线系统

    Unity射线系统 Demo展示 UI+Physical射线测试: FPS自定义射线测试: UGUI射线工具 实现功能,鼠标点击UI,返回鼠标点击的UI对象: 需要使用到鼠标点击事件-PointerE ...

  6. SprinMvc快速入门

    1.spring mvc Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架. 查看官方文档:https://docs.spring.io/sp ...

  7. Sending and Trapping Signals

    http://mywiki.wooledge.org/SignalTrap Signals are a basic tool for asynchronous interprocess communi ...

  8. .Net(c#)汉字和Unicode编码互相转换实例

    {"name": "\u676d\u5dde", "href": "www.baidu.com"} 经常遇到这样内容的j ...

  9. 数据流中的中位数 牛客网 剑指Offer

    数据流中的中位数 牛客网 剑指Offer 题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就 ...

  10. ACM 数据读写/对拍

    freopen()函数在ACM中的使用 - cfzjxz的专栏 - 博客频道 - CSDN.NET 在做acm题目的过程中,我们需要在本地机器上调试.调试过程中,如果输入数据少还可以接受,但如果输入数 ...