求区间 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;
}
可持久化线段树
维护每个数在第 个历史前,最后一次出现的位置
对于查询 ,在第 个历史版本中找到 最后一次在第 个历史版本最小值。
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效