首页 > 其他分享 >莫队学习笔记

莫队学习笔记

时间:2023-05-04 18:34:35浏览次数:28  
标签:200001 md int 笔记 学习 端点 include 莫队

概念

莫队是一种幽雅的暴力。用于处理区间问题。

核心思想就是把询问离线下来,然后维护双指针按一定顺序处理每个询问。精髓就在于一定顺序。

首先确定一个块长,然后将左端点的位置除以块长,把询问分成若干块。在每个块里按右端点排序。发现当块长为 \(\sqrt n\) 时两个指针各移动 \(n\sqrt n\) 次,然后做即可。

模板

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#define int long long
using namespace std;
int n,m,a[100001];
int ans[100001];
int sq;
struct item
{
	int l,r,md,i;
}fucl[1000001];
bool cmp(item a,item b)
{
	if(a.md==b.md) return a.r<b.r;
	return a.md<b.md;
}
void add(int w)
{
	//some
}
void del(int w)
{
	//some
}
signed main()
{
	freopen("god.in","r",stdin);
	freopen("god.out","w",stdout);
//	freopen("D:\\Astro\\C++\\GDOI\\down\\down\\sample\\A\\sample3.in","r",stdin);
//	freopen("D:\\Astro\\C++\\GDOI\\down\\down\\sample\\A\\sample3.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	sq=500;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld",&fucl[i].l,&fucl[i].r);
		fucl[i].md=fucl[i].l/sq;
		fucl[i].i=i;
	}
	sort(fucl+1,fucl+m+1,cmp);
	int l,r=0;
	l=1;
	for(int i=1;i<=m;i++)
	{
		while(r<fucl[i].r)
		{
			r++;
			add(a[r]);
		}
		while(r>fucl[i].r)
		{
			del(a[r]);
			r--;
		}
		while(l<fucl[i].l)
		{
			del(a[l]);
			l++;
		}
		while(l>fucl[i].l)
		{
			l--;
			add(a[l]);
		}
		ans[fucl[i].i]=/*some*/;
	}
	for(int i=1;i<=m;i++)
	{
		printf("%lld\n",ans[i]);
	}
}

回滚莫队

回滚莫队可以面对删点麻烦的情况,核心操作是撤销操作。

与普通莫队一样,我们对询问离线并按值域分块。假如我们在处理的块是左端点在 \([l,r]\) 中的。我们最开始把右端点放到 \(r\) 并初始化所有东西。因为右端点有序,所以直接扫过去。每次处理询问时先处理好右端点,然后左端点从 \(r\) 开始前移到目标位置,此时就获得了答案。再把左端点移动产生的贡献撤销。时间复杂度是 \(n\sqrt n\)。需要注意的是撤销的时间复杂度问题。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
int n,m,len,answ[200001],a[200001],lsh[200001],sq,fi[200001],la[200001],fii[200001],laa[200001],ans;
struct qw
{
	int l,r,md,i;
}q[200001];
bool vis[200001];
int use[200001],lenn;
bool cmp(qw a,qw b)
{
	if(a.md==b.md) return a.r<b.r;
	return a.md<b.md;
}
void add(int w,int i)
{
	la[w]=max(la[w],i);
	fi[w]=min(fi[w],i);
	ans=max(ans,la[w]-fi[w]);
}
signed main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		lsh[i]=a[i];
	}
	sort(lsh+1,lsh+n+1);
	for(int i=1;i<=n;i++)
	{
		a[i]=lower_bound(lsh+1,lsh+n+1,a[i])-lsh;
	}
	scanf("%lld",&m);
	sq=sqrt(n);
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld",&q[i].l,&q[i].r);
		q[i].md=q[i].l/sq;
		q[i].i=i;
	}
	sort(q+1,q+m+1,cmp);
	int l,r;
	q[0].md=-1;
	for(int z=1;z<=n;z++)
	{
		la[z]=-100000000;
		fi[z]=100000000;
	}
	r=(q[1].md+1)*sq;
	r--;
	for(int i=1;i<=m;i++)
	{
		if(q[i].md!=q[i-1].md)
		{
			r=(q[i].md+1)*sq;
			r--;
			for(int z=1;z<=n;z++)
			{
				la[z]=-100000000;
				fi[z]=100000000;
			}
			ans=0;
		}
		if(q[i].r<=(q[i].md+1)*sq) continue;
		while(r<q[i].r)
		{
			r++;
			add(a[r],r);
		}
		l=(q[i].md+1)*sq;
		int anss=ans;
		while(l>q[i].l)
		{
			l--;
			if(!vis[a[l]])
			{
				laa[a[l]]=la[a[l]];
				use[++lenn]=a[l];
				fii[a[l]]=fi[a[l]];
				vis[a[l]]=true;
			}
			laa[a[l]]=max(laa[a[l]],l);
			fii[a[l]]=min(fii[a[l]],l);
			anss=max(anss,laa[a[l]]-fii[a[l]]);
		}
		for(int z=1;z<=lenn;z++)
		{
			vis[use[z]]=false;
		}
		lenn=0;
		answ[q[i].i]=anss;
	}
	for(int i=1;i<=m;i++)
	{
		if(q[i].r<=(q[i].md+1)*sq)
		{
			int anss=0;
			for(int z=q[i].l;z<=q[i].r;z++)
			{
				if(!vis[a[z]])
				{
					laa[a[z]]=-100000000;
					use[++lenn]=a[z];
					fii[a[z]]=100000000;
					vis[a[z]]=true;
				}
				laa[a[z]]=max(laa[a[z]],z);
				fii[a[z]]=min(fii[a[z]],z);
				anss=max(anss,laa[a[z]]-fii[a[z]]);
			}
			answ[q[i].i]=anss;
			for(int z=1;z<=lenn;z++)
			{
				vis[use[z]]=false;
			}
			lenn=0;
		}
	}
	for(int i=1;i<=m;i++)
	{
		printf("%lld\n",answ[i]);
	}
}

标签:200001,md,int,笔记,学习,端点,include,莫队
From: https://www.cnblogs.com/lizhous/p/17372168.html

相关文章

  • 后缀数组学习笔记
    概念后缀数组,即对于一个串,它的每个后缀按字典序排序后得到的数组。有两个数组要求:\(SA_i\):排名为\(i\)的后缀的开头位置\(RK_i\):以\(i\)为开头的后缀的排名朴素sort排序一下优化倍增优化:我们进行\(\logn\)次排序,第\(k\)次取所有后缀的前\(2^k\)个字符进行......
  • 点分治学习笔记
    概念点分治用于解决有一定要求的链的计数。对于点\(u\)的子树的问题,可以将答案分为:经过点\(u\)不经过点\(u\)第一种可以用桶加暴力。枚举一端的长度,用桶计算另一端长度;第二种分到子树中解决即可。注意到,在随机选根的时候该算法表现不优秀,但若根为重心,因为每次子树......
  • 网络流学习笔记
    概念最大流:在一个网络图上,每个边有流量限制,假如起始点有无线流量,求最多能有多少流量流到终点。增广路:一条从起始点到终点了路径,可以流流量。算法Ford-Fulkerson算法解决这个问题,可以用Ford-Fulkerson算法。该算法的核心就是寻找增广路。每找到一条增广路,就给它它能承受......
  • 关于单片机控制电压检测的学习
    1.使用单片机内自带的ADC模块进行检测问题在于频率是否合适:在实验2的基础上得到结论,当两线圈距离在2cm左右时,工作频率将会超过1MHz。采样的最好结果是采集尽可能多的点,这样才能绘制出真正反映实际情况的曲线。目前想要完成的是实验3的demo,采用电阻分压和二极管整流,直接利用......
  • python-Gradio 机器学习演示库
    python-GradioGradio是一个开源的Python库,用于构建机器学习和数据科学演示应用。有了Gradio,你可以围绕你的机器学习模型或数据科学工作流程快速创建一个简单漂亮的用户界面。Gradio适用于以下情况:为客户/合作者/用户/学生演示你的机器学习模型。通过自动共享链接快速部署你的......
  • 学习使用benchmarksql压测数据库
    介绍benchmarksql是一款符合TPC-C基准压力测试工具,TPC-C是衡量在线事务处理的基准。TPC-C模型是模拟一个商品批发公司的销售模型,这个模型涵盖了一个批发公司面向客户对一系列商品进行销售的过程,这包括管理订单,管理库存,管理账号收支等操作。这些操作涉及到仓库、商品、客户、订单......
  • TypeScript 学习笔记 — 模板字符串和类型体操(十五)
    目录基本介绍字符串类型体操实操环节1.字符串首字母大写CapitalizeString2.获取字符串第一个字符FirstChar3.获取字符串最后一个字符LastChar4.字符串转元组StringToTuple5.元组转字符串TupleToString6.重复字符串RepeatString7.字符串分割SplitString8.获取字符串......
  • react.js学习笔记
    (1)      参考文献1.前端技术手册2.在线编码......
  • 内网工控机通过联网笔记本上网
    1、工控机与笔记本通过网卡连接。2、笔记本win11,工控机ubuntu14.043、笔记本设置共享上网  参考https://zhidao.baidu.com/question/505682783651825564.html,此文。  1)打开控制面板,进入WLAN的属性界面    2)确定后出现一个提示,笔记本的本地连接变成192.168......
  • 最优控制和轨迹规划学习笔记
    最优控制和轨迹规划学习笔记包含多个实际案例倒立摆上翻控制满足车辆运动学约束的路径规划离散点参考线优化lattice横向距离规划YID:5745658004330616......