首页 > 其他分享 >【GJOI 2023.10.17 T4】 莫队

【GJOI 2023.10.17 T4】 莫队

时间:2023-10-17 15:57:23浏览次数:36  
标签:nxt minn min T4 long merge 区间 GJOI 莫队

莫队

今天,接触信息学不久的小 A 刚刚学习了莫队。
莫队可以解决一类难以合并,但方便插入的信息维护。比如,给定一个序列,支持单点修改,每次询问一个区间出现了多少种数字。再比如,给定一个序列,支持单点修改,每次询问区间众数。诸如此类。
小 A 觉得这样的情况太平凡了。于是,他定义了一个区间是无重的,当且仅当区间内没有重复的数字。具体的,一个区间 \([l,r]\) 无重,当且仅当 \(\forall l\le i< j \le r\) ,都有 $ a_i\not=a_j $ 。
他给定了一个长度为 \(n\) 序列 \(a\),并给出 \(m\) 组操作:每次修改一个位置的数,或者询问一个区间 \([l,r]\) 中,有多少个无重的子区间。

解题思路

首先,对于一个数 \(x\) ,它后面第一个和它重复的数定义为 \(nxt_x\) 。
很明显,对于一个区间中的一个数 \(a\) ,设 \(b\) 为区间左端点,若 \(x \in [a,b]\) 有 \(b < nxt_x\) ,区间 \([a,b]\) 都能满足条件。
就是 \(b<min(nxt_x) ,\) \(x \in [a,b]\) 。
\(min(nxt_x)\) 实在不断变小的,所以 \(b\) 实在不断变小的。
所以,对于区间 \([l,r]\) 中的一个数 \(a\) ,它能取到的右端点定小于 \(min(nxt_x),x \in [a,r]\) 。
从左往右看,就是每次往 \(min\) 集合中添一个数,求每次加之后的的最小值减去当前的左端点 \(a\) 。
提出 \(a\) 来,就是求 \(min(nxt_r)+min(nxt_{r-1},nxt_r)+......+min(nxt_l,......nxt_r)\) 。
考虑如何维护这个东西。
做一个线段树,维护 \(minn,f\) ,\(minn\) 就是区间最小值, \(f\) 就是一个区间内的答案。
在线段树外面开个 \(set\) ,用于由原数组来动态维护 \(nxt\) 。
每次修改 \(nxt\) ,在线段树上修改。
上传时先上传 \(minn\) ,对于 \(f\) ,我们设计一个函数 \(merge(x,l,r,v)\) 来维护一个区间的答案,参数分别代表当前做的区间,区间左端点与右端点,以及 \(min\) 集合中的最小值。
设右儿子区间的 \(minn\) 为 \(x\) ,若 \(x<v\) 说明左儿子区间不会变化,答案为 \(f_x-f_{rc}+merge(rc,mid+1,r,v)\) 。
否则,右儿子区间内答案为 \((r-mid)*v\) ,左儿子答案为 \(merge(lc,l,mid,v)\) 。
\(f_x\) 即为 \(f[rc]+merge(lc,l,mid,minn[rc])\) 。
一次修改时间复杂度 \(O(log^2n)\) 。
而查询时,我们可以继续利用 \(merge\) 函数,将查询区间按线段树划分方法划成一个个区间,从右往左用 \(merge\) 函数合并,最后就是答案。
减去左端点的和 \((l+r)(r-l+1)/2\) 即可。
一次查询时间复杂度 \(O(log^2n)\) ,总时间复杂度 \(O((n+m)logn)\) 。

Code

#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
using namespace std;
long long n,m,minn[800005],f[800005],s=0,a[200005],nxt[200005],rr;
set<long long> l[200005];
long long merge(long long x,long long l,long long r,long long v)
{
	if(l==r)return min(v,minn[x]);
	long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
	if(minn[rc]<=v)return f[x]-f[rc]+merge(rc,mid+1,r,v); 
	return v*(r-mid)+merge(lc,l,mid,v); 
}
void up(long long x,long long l,long long r)
{
	long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
	minn[x]=min(minn[lc],minn[rc]);
	f[x]=f[rc]+merge(lc,l,mid,minn[rc]);
	return;
}
void dijah(long long x,long long l,long long r,long long k,long long v)
{
	if(l==r)
	{
		minn[x]=v;
		f[x]=v;
		return;
	}
	long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
	if(k<=mid)dijah(lc,l,mid,k,v);
	else dijah(rc,mid+1,r,k,v);
	up(x,l,r);
	return;
}
void gaia(long long x,long long l,long long r,long long ql,long long qr)
{
	if(ql<=l&&r<=qr)
	{
		s+=merge(x,l,r,rr);
		rr=min(rr,minn[x]);
		return;	
	}
	long long lc=(x<<1),rc=(x<<1)|1,mid=(l+r)>>1;
	if(qr>mid)gaia(rc,mid+1,r,ql,qr); 
	if(ql<=mid)gaia(lc,l,mid,ql,qr);
	return;
}
int main()
{
	long long p,x,y,qwe=0;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=4*n;i++)f[i]=minn[i]=n+1;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		l[a[i]].insert(i);
	}
	set<long long>::iterator q,w,e;
	for(int i=0;i<=n;i++)
	{
		if(l[i].size()==0)continue;
		q=l[i].begin();
		w=q;
		w++;
		for(;w!=l[i].end();q++,w++)
		{
			dijah(1,1,n,*q,*w);
			nxt[*q]=*w;
		} 
		dijah(1,1,n,*q,n+1);
		nxt[*q]=n+1;
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&p,&x,&y);
		if(p==1)
		{
			w=l[a[x]].find(x);
			if(w!=l[a[x]].begin())
			{
				q=w;
				e=w;
				q--;
				e++;
				if(e!=l[a[x]].end())
				{
					dijah(1,1,n,*q,*e);
					nxt[*q]=*e;
				}
				else
				{
					nxt[*q]=n+1;
					dijah(1,1,n,*q,n+1);
				}
			}
			l[a[x]].erase(w);
			a[x]=y;
			l[y].insert(x);
			w=l[y].find(x);
			e=w;
			e++;
			if(e!=l[y].end())
			{
				dijah(1,1,n,*w,*e);
				nxt[*w]=*e;
			}
			else
			{
				dijah(1,1,n,*w,n+1);
				nxt[*w]=n+1;
			}
			if(w!=l[y].begin())
			{
				q=w;
				q--;
				dijah(1,1,n,*q,*w); 
				nxt[*q]=*w;
			}
		}
		else 
		{
			if(x>y)swap(x,y);
			rr=y+1;
			s=0;
			gaia(1,1,n,x,y);
			printf("%lld\n",s-(y-x+1)*(x+y)/2);
			s=0;
		}
	}








  return 0;
}

标签:nxt,minn,min,T4,long,merge,区间,GJOI,莫队
From: https://www.cnblogs.com/dijah/p/17769896.html

相关文章

  • [刷题笔记] CSP-J 2022 T4 上升点列
    Description在一个二维平面内,给定\(n\)个整数点\((x_i,y_i)\),此外你还可以自由添加\(k\)个整数点。你在自由添加\(k\)个点后,还需要从\(n+k\)个点中选出若干个整数点并组成一个序列,使得序列中任意相邻两点间的欧几里得距离恰好为\(1\)而且横坐标、纵坐标值均单调不......
  • GODOT4 按键重映射
    创建按钮创建Button节点,勾选属性Togglemode创建脚本在按钮上创建gb脚本在脚本中键入如下代码:@exportvaraction:String="ui_accept"#要重映射的动作名称[项目设置->输入映射]中的名称在gb脚本的_ready()方法中键入如下代码:func_ready(): #set_focu......
  • 还不会在MT4用Renko,FPmarkets澳福手把手教你一分钟学会
    很多投资者还不会在MT4上使用Renko,让FPmarkets澳福通过一个具体的例子来探讨,Renko图表指标在MT4平台上的应用,以AG Renko为例。首先,投资者需要解压缩下载的档案,并将其移动到MT4的“指标”文件夹中。重启MetaTrader交易平台后,所添加的工具就会出现在指标列表中。若要将AG Renko添加......
  • 树上莫队小技巧
    前言联考有一道树上莫队一眼题,但是我还没学过树上莫队啊!!!于是开始口胡,这个东西好像是说这个东西把树拍成欧拉序,端点一移动,做完了!开始写,一下子过大样例,没有细节!然后在网上一看树上莫队的博客:大家怎么都求了LCA?为什么要分讨有祖先后代关系的情况?坏了,一定是我做法假了!!!然后往SPOJ......
  • P9233 [蓝桥杯 2023 省 A] 颜色平衡树 (dfs序 莫队)
    P9233[蓝桥杯2023省A]颜色平衡树(dfs序莫队)莫队原理:https://zhuanlan.zhihu.com/p/115243708对于树上的每个结点,按照dfs序打上时间戳,这样就可以把每一个结点对应的子树的答案转化为一个区间的答案。将子树询问离线下来变成\(n\)个区间查询。用\(cnt\)数组维护颜色......
  • 【离线算法】- 莫队
    莫队简介莫队是可以支持多次询问区间\([l,r]\)的信息的离线算法。通过将询问范围以块长为\(\sqrtn\)分块后按端点所属分块排序的方式优化复杂度。普通莫队定义普通莫队针对的是序列上的区间询问。常见形式为:对于一个长度为\(n\)的序列,提出\(m\)次询问,每次询问区间......
  • 树上莫队
    20231012树上莫队由于联考考到,又直接爆0,于是来学习。树上莫队——把莫队放到树上。但我是真的不知道把莫队怎么放到树上。。。于是我们考虑一个东西叫做欧拉序,就是再dfs的时候在进栈和出栈的地方都记录一下。而在区间查询的时候,我们只对区间出现一次的数统计答案,用一个......
  • 二次离线莫队笔记
    前言莫队可以解决许多其他数据结构无法完成的问题,正在很多其他问题上也可以拿部分分甚至满分,只因其复杂度为小常数\(O(n\sqrtn\timesk)\)其中\(k\)是单次扩张以及收缩的复杂度,而二离莫队可以在答案可差分的情况下达到\(O(n\sqrtn+n\timesk)\)起源lxl把二次离线莫......
  • 在线莫队
    我竟然独立发现了这个东西...考虑普通的莫队就是让区间加元素操作尽可能少,那么对于所谓的在线莫队,我们可以先跑出一些标准区间的值,然后在对他进行拓展,最终得出结果。我们均匀的取出\(B\)个关键点,然后对于两两关键点算出答案。那么我们拓展区间时,最多要拓展\(O(\frac{n^2}{B})......
  • qbxt 突破营 Day1 T4
    考虑经典的俄罗斯方块游戏,二维平面上有若干个积木,他们会受重力的影响下落并堆叠。注意,积木只会竖直下落,如果下落过程中碰到了别的积木那么就会停下。例如下图:不同颜色的块代表了不同的积木,这些积木下落之后会形如下图:积木的形状可以任意的,可能跟传统的俄罗斯方块有一些不同,比......