莫队 学习笔记

news/2024/12/21 16:36:07/文章来源:https://www.cnblogs.com/CodingGoat/p/18620909

阅前声明

题单
为方便,题目链接均在洛谷。

要用桶的时候请尽量不要使用 map 或者 un_map,会造成不必要的 TLE。

普通莫队

当一个区间问题,可以由 \([l,r]\) 转移到 \([l\pm 1,r]\)\([l,r\pm 1]\),且添加、删除都可以已很快的时间完成时,我们可以使用莫队算法。
我们先将询问离线下来,并将他们排序。我们先把数列分为若干个块,块长为 \(S\),则先按 \(l\) 所在的区间排序,再按 \(r\) 的大小排序。
对于每一个询问,我们对于上个区间暴力转移到下个区间。可行转移方式之一是先扩大区间再缩小区间。
\(S=\sqrt{n}\) 时,时间复杂度为 \(n\sqrt{n}\)

莫队的主体,按上面实现的话,应该是长这样:

int l=1,r=0;
For(i,1,m) {while(l>q[i].l) upd(a[--l]);while(r<q[i].r) upd(a[++r]);while(l<q[i].l) del(a[l++]);while(r>q[i].r) del(a[r--]);ans[q[i].idx]=sum;
}

DQUERY - D-query

题意:区间不同数

莫队主体是简单的,于是我们考虑加入和删除。
我们可以开一个桶保存每个数出现的次数:

  • 加入时如果保存该数的桶为空,那么答案加 \(1\)
  • 删除后如果保存该数的桶为空,那么答案减 \(1\)
  • 然后对桶进行操作即可。
点击查看代码
#include<bits/stdc++.h>#define ll long long
#define i128 __int128#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()using namespace std;int read() {int x=0,f=1; char c=getchar();for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1); for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);return x*f;
}
void write(int x) { if(x>=10) write(x/10); putchar('0'+x%10); }const int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }#define maxn 200050int n,m,siz;
map<int,int> cnt;
int a[maxn];struct node{int l,r,idx;bool operator<(const node &x) {return l/siz==x.l/siz?r<x.r:l<x.l;}
}q[maxn];int sum=0;void upd(int x) {if(cnt[x]==0) sum++;cnt[x]++;
}void del(int x) {if(cnt[x]==1) sum--;cnt[x]--;
}int ans[maxn];void work() {in1(n);siz=sqrt(n);For(i,1,n) in1(a[i]);in1(m);For(i,1,m) in2(q[i].l,q[i].r),q[i].idx=i;sort(q+1,q+m+1);int l=q[1].l,r=q[1].l-1;For(i,1,m) {while(l>q[i].l) upd(a[--l]);while(r<q[i].r) upd(a[++r]);while(l<q[i].l) del(a[l++]);while(r>q[i].r) del(a[r--]);ans[q[i].idx]=sum;}For(i,1,m) cout<<ans[i]<<'\n';
}signed main() {
//	ios::sync_with_stdio(false); 
//	cin.tie(0); cout.tie(0);int _=1;
//	_=read();For(i,1,_) {work();}return 0;
}

P1494 [国家集训队] 小 Z 的袜子

题意:求区间 \([l,r]\) 中随机选出两个数相等的概率。

简单计数题。
用一个桶 \(cnt\) 保存每一个数出现的次数,考虑一个数 \(x\) 的贡献。

  • 加入 \(x\) 前,会对答案产生 \(cnt_x\) 的贡献。
  • 删除 \(x\) 后,会对答案造成 \(-cnt_x\) 的贡献。
点击查看代码
#include<bits/stdc++.h>
#define int ll
#define ll long long
#define i128 __int128#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()using namespace std;int read() {int x=0,f=1; char c=getchar();for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1); for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);return x*f;
}
void write(int x) { if(x>=10) write(x/10); putchar('0'+x%10); }const int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }#define maxn 50040
int n,m,siz;
int a[maxn],cnt[maxn];
struct quest{int l,r,idx;
}q[maxn];
bool cmp(quest a,quest b) {return a.l/siz==b.l/siz?a.r<b.r:a.l<b.l;
}
pair<int,int> ans[maxn];int sum=0;
void upd(int x) {sum+=cnt[x]; cnt[x]++; }
void del(int x) {cnt[x]--; sum-=cnt[x]; }void work() {in2(n,m);For(i,1,n) in1(a[i]);For(i,1,m) in2(q[i].l,q[i].r),q[i].idx=i;siz=sqrt(n);sort(q+1,q+m+1,cmp);int l=q[1].l,r=q[1].l-1;For(i,1,m) {if(q[i].l==q[i].r) {ans[q[i].idx].first=0;ans[q[i].idx].second=1;continue ;}while(l>q[i].l) upd(a[--l]);while(r<q[i].r) upd(a[++r]);while(l<q[i].l) del(a[l++]);while(r>q[i].r) del(a[r--]);ans[q[i].idx].first=sum;ans[q[i].idx].second=(r-l+1)*(r-l)/2;if(!ans[q[i].idx].first) ans[q[i].idx].second=1;}For(i,1,m) {int G=__gcd(ans[i].first,ans[i].second);cout<<ans[i].first/G<<'/'<<ans[i].second/G<<'\n';}
}signed main() {
//	ios::sync_with_stdio(false); 
//	cin.tie(0); cout.tie(0);int _=1;
//	_=read();For(i,1,_) {work();}return 0;
}

XOR and Favorite Number

询问 \([l,r]\) 中有多少个区间满足区间的异或和为 \(k\)

首先我们知道 \(\oplus\) 是可以前缀和的。
然后求一段区间 \([l,r]\) 的异或和可以转换为前缀异或数组 \(s\)\(s_{r}\oplus s_{l-1}\)
所以答案变为求 \([l,r]\)\(s_x \oplus s_y = k(x\le y)\)\(\{x,y\}\) 对数。
我们用一个桶 \(cnt\) 来保存每个数的出现次数,那么:

  • 加入 \(x\) 前,会对答案产生 \(cnt_{x\oplus k}\) 的贡献。
  • 删除 \(x\) 后,会对答案产生 \(-cnt_{x\oplus k}\) 的贡献。
点击查看代码
#include<bits/stdc++.h>
#define int ll
#define ll long long
#define i128 __int128#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()using namespace std;int read() {int x=0,f=1; char c=getchar();for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1); for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);return x*f;
}
void write(int x) { if(x>=10) write(x/10); putchar('0'+x%10); }const int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }#define maxn 100050int n,m,k,siz;
int a[maxn];
int cnt[maxn*20];
ll sum=0;struct quest{int l,r,idx;bool operator<(const quest &x) const{return l/siz==(x.l/siz)?r<x.r:l<x.l;}
}q[maxn];void upd(int x) {sum+=cnt[x^k];cnt[x]++;
}void del(int x) {cnt[x]--;sum-=cnt[x^k];
}
int ans[maxn];void work() {in3(n,m,k);siz=sqrt(n);For(i,1,n) in1(a[i]);For(i,1,n) a[i]^=a[i-1];For(i,1,m) {in2(q[i].l,q[i].r);q[i].l--;//前缀和导致的q[i].idx=i;}sort(q+1,q+m+1);int l=1,r=0;For(i,1,m) {while(l>q[i].l) upd(a[--l]);while(r<q[i].r) upd(a[++r]);while(l<q[i].l) del(a[l++]);while(r>q[i].r) del(a[r--]);ans[q[i].idx]=sum;}For(i,1,m) cout<<ans[i]<<'\n';
}signed main() {
//	ios::sync_with_stdio(false); 
//	cin.tie(0); cout.tie(0);int _=1;
//	_=read();For(i,1,_) {work();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/856399.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flash动画综合设计

Flash动画综合设计并发布、嵌入到网页【作业要求】 自己选定主题,创意制作Flash动画,并与网页进行集成 【实验环境】 l 所需硬件环境为微机; l 所需软件环境为Flash8.0 【创意内容】一、国旗飘荡效果设计思路:我选择了中国国旗作为主题,想通过动态效果让国旗看起来像在风中…

意念力

点分治 分治fft 下降幂多项式题目链接 很有道理的题。把划分集合的方案容斥一下,变成染色的方案。 再从边界情况考虑问题。 链 设当前钦定有 \(x\) 种颜色。 从前往后考虑每个点的贡献。 容易发现,它与在它之前的 k-邻域内任意一点颜色不同即可满足条件。 而它之前 k-邻域内的…

JVM专题学习之类加载器(二)

类加载器 三层类加载器 1.启动类加载器-BootstrapClassLoader AppClassLoader负责加载核心类,存放在lib目录下的jar包或class文件。 2.扩展类加载器-ExtensionClassLoader ExtensionClassLoader负责加载\lib\ext目录下的jar包或class文件,我们可以将通用性的功能,打成jar包放…

2024-2025-1 20241417 《计算机基础与程序设计》第十三周学习总结

2024-2025-1 20241417 《计算机基础与程序设计》第十三周学习总结 作业信息这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>2024-2025-1计算机基础与程序设计第十三周作业这个作业的目标 <复习前…

28.Python基础篇-logging模块

介绍: logging 模块是Python内置的强大日志记录工具,支持多种输出方式、格式化选项及多进程支持。 日志的级别 logging 模块有五个内置的日志级别,从低到高:DEBUG:详细信息,用于诊断问题。 INFO:常规信息,表示程序正常运行的状态。 WARNING:警告信息,表示潜在问题或即…

Redis安装配置

安装gcc环境sudo yum install -y gcc-c++查看gcc环境gcc -v

我们的电视Our tv 3.6.0安卓+TV 一款全新电视直播软件-内置稳定直播源

应用简介 我们的电视(ourtv)是一款完全无广告的电视直播软件,清晰度可选择高清,超清,蓝光等播放。安装即可使用,再也不用费劲去找各种不稳定的直播源了。 “我们的电视”播放线路(直播源)是来自央视频,因此画质和稳定性还可以。不过随之而来的问题是跟央视频 App 不兼…

[HTML/Web] HTML5之`Video`元素

概述:video 元素 核心属性:playbackRate/播放速率在HTML5中,<video> 元素提供了一个 playbackRate 属性,可以用来设置视频的播放速度。这个属性允许你设置视频的倍速播放,比如正常速度、慢速或快速。以下是如何设置 <video> 元素的倍速播放:html<video id…

鸿蒙HarmonyOS应用开发 | HarmonyOS Next-从应用开发到上架全流程解析

HarmonyOS Next-从应用开发到上架全流程解析 随着智能设备的不断普及,操作系统的竞争变得愈加激烈。在这个背景下,华为推出的HarmonyOS(鸿蒙操作系统)逐渐崭露头角,成为一个引人注目的新兴平台。本文将深入探讨HarmonyOS Next的应用开发流程,并特别关注鸿蒙应用上架的全过…

2024-2025-1 20241307《计算机基础与程序设计》第十三周学习总结

作业信息这个作业属于哪个课程 (2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 ([2024-2025-1计算机基础与程序设计第十三周作业]这个作业的目标作业正文 (2024-2025-1 学号20241307《计算机基础与程序设计》第十三周学习总结)教材学习内容总结 C语言程序设计第十二…

移动端笔记应用,markdown应用选用

要求不能有广告。作为使用频率较高的软件,有广告就是恶心人。 支持markdown,包括且不限于代码块、标题、图片等格式。 支持同步,至少拥有WebDav云同步,或者本地导入导出。 全局搜索功能。以上功能必须免费,至少我不明白导入导出有什么好付费的。云同步这种付费理所当然。背…

一个.NET开源、易于使用的屏幕录制工具

前言 一款高效、易用的屏幕录制工具能够极大地提升我们的工作效率和用户体验,今天大姚给大家分享一个.NET开源、免费、易于使用的屏幕录制工具:Captura。 工具介绍 Captura是一款基于.NET开源、免费、易于使用的屏幕录制、截图工具,允许用户录制屏幕活动、捕获屏幕截图、录制…