待修改莫队与普通莫队优化

待修改莫队与普通莫队优化

普通莫队比较简单,先不讲了。

奇偶华排序

观察数据:

复制代码
1 1 
2 100
3 1
4 100

显然这么排会浪费许多时间,构造排列:

复制代码
1 1
3 1
2 100
4 100

这样可以极大地减少指针移动次数。

就是将 l l l 指针的所在块进行分类,如果是奇数块就从小到大排,否则从大到小排。

可以玄学优化 30 % 30\% 30% 的时间(逃

待修改莫队

普通莫队是不可以修改的,但是我们可以强行让其可以单点修改。

我们在普通莫队的基础上维护一维时间维。

我们定义时间是修改的顺序编号,即第几个修改操作。

具体地:

  • 单点修改,把某一位的数字修改掉。对于现在这个询问,如果当前区间的时间比它小,则暴力增加修改操作。否则撤销操作。
  • 增加操作:如果操作的位置在区间内,则删除原数字,增加改动的数字。如果不在,直接修改数组。
  • 撤销操作:即增加的逆操作。

例题

P1903 【模板】带修莫队 / 国家集训队 数颜色 / 维护队列

代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ljl;
#define FUP(i,x,y) for(auto i=(x);i<=(y);++i)
#define FDW(i,x,y) for(auto i=(x);i>=(y);--i)
inline void Rd(auto &num);
const int N=133335,K=1e6+5;
int n,m,cnt[K],cntc,cntq,pos[N],curl,curr,curc,ans[N],sum,a[N];
void blk()
{
	int blksz=(int)pow(n,2.0/3.0);
	FUP(i,1,n)
		pos[i]=(i-1)/blksz+1;
	return;
}
struct C{
	int p,c;
}c[N];
struct Q{
	int l,r,uid,tim;
	bool operator < (const Q &x)const{
		if(pos[l]!=pos[x.l])return pos[l]<pos[x.l];
		if(pos[r]!=pos[x.r])
		{
			if(pos[l]&1)
				return pos[r]<pos[x.r];
			return pos[r]>pos[x.r];
		}
		return tim<x.tim;
	}
}q[N];
void add(int x)
{
	if(!cnt[x])++sum;
	++cnt[x];
	return;
}
void del(int x)
{
	if(cnt[x]==1)--sum;
	--cnt[x];
	return;
}
void getch(char &ch)
{
	ch=getchar();
	while(ch!='Q'&&ch!='R')ch=getchar();
	return;
}
void upd(int i,int curc)
{
	if(q[i].l<=c[curc].p&&c[curc].p<=q[i].r)
	{
		del(a[c[curc].p]);
		add(c[curc].c);
	}
	swap(a[c[curc].p],c[curc].c);//小技巧:下次操作一定是反着的
	return;
}
int main(){
	Rd(n);Rd(m);
	blk();
	FUP(i,1,n)Rd(a[i]);
	for(int i=1,l,r;i<=m;++i)
	{
		char ch;getch(ch);
		Rd(l);Rd(r);
		if(ch=='Q')
		{
			q[++cntq].l=l;q[cntq].r=r;
			q[cntq].uid=cntq;q[cntq].tim=cntc;
		}
		else{
			c[++cntc].p=l;c[cntc].c=r;}
	}
	sort(q+1,q+cntq+1);curl=1;curr=0;curc=0;
	FUP(i,1,cntq)
	{
		while(q[i].l<curl)add(a[--curl]);
		while(curr<q[i].r)add(a[++curr]);
		while(curl<q[i].l)del(a[curl++]);
		while(q[i].r<curr)del(a[curr--]);
		while(curc<q[i].tim){
			++curc;upd(i,curc);}
		while(curc>q[i].tim){
			upd(i,curc);--curc;}
		ans[q[i].uid]=sum;
	}
	FUP(i,1,cntq)
		printf("%d\n",ans[i]);
	return 0;
}
inline void Rd(auto &num)
{
	num=0;char ch=getchar();bool f=0;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		num=(num<<1)+(num<<3)+(ch-'0');
		ch=getchar();
	}
	if(f)num=-num;
	return;
}
相关推荐
机器人零零壹35 分钟前
技术白皮书:iRobotCAM如何解决机器人激光切割应用中的核心难点,从CAD离线编程到双目视觉定位与轨迹自适应提升复杂空间曲线切割的精度、效率与柔性化水平
人工智能·算法
AI你一生一世2 小时前
不止于时序存储:DolphinDB 如何成为 AI 时代的工业智能底座
java·人工智能·struts·时序数据库·工业智能·dolphindb·ai基础设施
belldeep2 小时前
python:genesis-world, Genesis-Embodied-AI
人工智能·python·ai·genesis
布莱克6052 小时前
C/C++ 中变量的声明与定义:区别、联系与常见误区
c语言·开发语言·c++·声明·定义
云-缩影2 小时前
拆解 AI 图像生成应用的后端架构:ECS、OSS 和大模型 API 怎么配合
java·spring boot·后端
瑞克-桑切斯2 小时前
7、MySQL 慢查询排查与优化实战指南
java·服务器·数据库
benchmark_cc3 小时前
A 股、港股、美股如何建立统一的标的主数据格式?
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
ZhengEnCi3 小时前
大模型的分类到底怎么分:从基础模型到推理模型、从通用到专用的完整图谱
算法
维克兜率天3 小时前
【维克】趋势型CTA:期货市场的“追涨杀跌“
人工智能·python
前进的李工4 小时前
Agent 学习笔记 05:系统提示词应该怎么写
笔记·学习·prompt·agent·个人开发·few-shot·ai应用开发