「CF522D Closest Equals」

题目大意

给出一个序列,每次查询一段区间内距离最近的相同元素之间的距离.

分析

RMQ+二分的做法好妙啊,我就根本想不出来.

考虑一个数对只有当两个数相等且都在区间内才可能会产生贡献.

记录一个 \(pre_i\) 表示第 \(i\) 个数相同的数上一次出现的位置

这个东西就很像区间取 \(\min\) 了,将 \(i\)\(pre_i\) 的贡献放在 \(pre_i\) 的位置,那么这个区间查询的答案就是 \(l\sim r\) 中记录的贡献的最小值了.

可是直接这样搞可能会导致 \(i\) 在区间外 \(pre_i\) 在区间内的情况出现,那么就考虑将查询离线下来,按右端点排序,只有当 \(i\leq right\) 时才将贡献放在 \(pre_i\) 上.

代码

#include
#define REP(i,first,last) for(int i=first;i<=last;++i)
#define DOW(i,first,last) for(int i=first;i>=last;--i)
using namespace std;
const int MAXN=5e5+5;
const int INF=1e9;
int n,m;
int arr[MAXN];
struct Sor
{
	int num,id;
}sor[MAXN];
bool Cmp(Sor a,Sor b)
{
	return a.num>b.num;
}
struct SegmentTree//一颗维护区间 min 的线段树
{
	int min;
}sgt[MAXN*4];
#define LSON (now<<1)
#define RSON (now<<1|1)
#define MIDDLE ((left+right)>>1)
#define LEFT LSON,left,MIDDLE
#define RIGHT RSON,MIDDLE+1,right
#define NOW now_left,now_right
void PushUp(int now)
{
	sgt[now].min=min(sgt[LSON].min,sgt[RSON].min);
}
void Build(int now=1,int left=1,int right=n)
{
	if(left==right)
	{
		sgt[now].min=INF;
		return;
	}
	Build(LEFT);
	Build(RIGHT);
	PushUp(now);
}
void Updata(int place,int num,int now=1,int left=1,int right=n)//单点修改
{
	if(right

这个东西怎么搞在线 \(\mathcal{O}(m\log n)\)

建可持久化线段树就好了.

你可能感兴趣的:(「CF522D Closest Equals」)