求区间 mex

莫队+分块

值域分块,每个块处理有多少个书出现过。

#include <bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
	x=0;
	int f=1;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')f=-1;
		c=getchar();
	}
	while('0'<=c&&c<='9')
	{
		x=(x<<1)+(x<<3)+c-'0';
		c=getchar();
	}
	x*=f;
}
const int N=2e5+5,B=448;
int n,m,a[N],id[N],block,cnt[N],num[N];
int ans[N];
struct node 
{
	int l,r,id;
}q[N];
bool cmp(node u,node v)
{
	if(id[u.l]==id[v.l])return u.r<v.r;
	return id[u.l]<id[v.l];
}
void del(int x)
{
	if(cnt[x]==1)num[x/B]--;
	cnt[x]--;
}
void add(int x)
{
	if(cnt[x]==0)num[x/B]++;
	cnt[x]++;
}
void query(int x)
{
	for(int i=1;i<=B;i++)
        if(num[i-1]!=B)for(int j=(i-1)*B;j<i*B;j++)if(!cnt[j])ans[x]=j;return;}
}
int main()
{
	read(n),read(m);
	block=sqrt(n);
	for(int i=1;i<=n;i++)
	{
		read(a[i]);
		id[i]=(i-1)/block+1;
	}
	for(int i=1;i<=m;i++)
	{
		read(q[i].l),read(q[i].r);
		q[i].id=i;
	}
	sort(q+1,q+m+1,cmp);
	int l=q[1].l,r=q[1].r;
	for(int i=l;i<=r;i++)add(a[i]);
	query(q[1].id);
	for(int i=2;i<=m;i++)
	{
		while(l<q[i].l)del(a[l++]);
		while(l>q[i].l)add(a[--l]);
		while(r<q[i].r)add(a[++r]);
		while(r>q[i].r)del(a[r--]);
		query(q[i].id);
	}
	for(int i=1;i<=m;i++)
	{
		cout<<ans[i]<<'\n';
	}
	return 0;
}

可持久化线段树

维护每个数在第 \(i\) 个历史前,最后一次出现的位置

对于查询 \([l,r]\),在第 \(r\) 个历史版本中找到 最后一次在第 \(l\) 个历史版本最小值。

#include <bits/stdc++.h>
using namespace std;
const int N=3e5+5,mx=3e5;
int n,m,b[N];

struct node
{
	int val,ls,rs;
}t[N*40];
int idx=0,rt[N];

namespace tree
{

inline void upd(int &p,int pre,int l,int r,int x,int k)
{
	p=++idx;
	t[p]=t[pre];
	if(l==r) { t[p].val=k; return; }
	int mid=(l+r)/2;
	if(x<=mid)upd(t[p].ls,t[pre].ls,l,mid,x,k);
	else upd(t[p].rs,t[pre].rs,mid+1,r,x,k);
	t[p].val=min(t[t[p].ls].val,t[t[p].rs].val);
}

inline int query(int p,int l,int r,int k)
{
	if(l==r)return l;
	int mid=(l+r)/2;
	if(t[t[p].ls].val<k)return query(t[p].ls,l,mid,k);//如果左子树的值域中,有最近一次出现的时间<当前查询的k时刻的点,就确定是左子树
	else return query(t[p].rs,mid+1,r,k);//否之,去右子树
}

inline int mex(int l,int r)
{
	if(l>r)return 0;
	return query(rt[r],0,n,l);//查询
}

}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
		tree::upd(rt[i],rt[i-1],0,n,b[i],i);
	}
	while(m--)
	{
		int st,en;
		cin>>st>>en;
		cout<<tree::mex(st,en)<<'\n';
	}
	return 0;
}
posted @ 2024-10-30 18:29  tyccyt  阅读(11)  评论(0)    收藏  举报