题目链接:点击查看
题目大意:给出一个长度为 n 的排列,再给出 m 次询问,每次询问需要回答区间 [ l , r ] 的 mex
题目分析:算是一道比较经典的题目了吧,先说一般做法,一般做法是 nlogn 的主席树,或者离线线段树,或者是 nsqrt( n ) 的莫队,这里我选择了比较好理解的主席树存一下,主席树的话就是每一个版本的线段树储存一下 [ 1 , i ] 中每个数字最后一次出现的位置,这样每次查询 [ l , r ] ,只需要在第 r 个版本的线段树中查询最小的那个没有出现的数字即可
而这个题目给的恰好是一个 n 的排列,也就是任意两个数都互不相同,这样就可以稍微思考一下优化为 O( n ) 的了,可以从前到后以及从后到前维护两个数组,mmin1 代表的是前缀最小值,mmin2 代表的是后缀最小值,每次对于 [ l , r ] 的查询来说,mmin1[ l - 1 ] 和 mmin2[ r + 1 ] 的最小值就是答案了,想一下是不是非常巧妙
代码:
主席树
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
struct Node
{
int l,r;
int sum;
}tree[N*20];
int cnt,root[N];
void init()
{
root[0]=0;
tree[0].l=tree[0].r=tree[0].sum=0;
cnt=1;
}
void update(int num,int &k,int l,int r)
{
tree[cnt++]=tree[k];
k=cnt-1;
tree[k].sum++;
if(l==r)
return;
int mid=l+r>>1;
if(num<=mid)
update(num,tree[k].l,l,mid);
else
update(num,tree[k].r,mid+1,r);
}
int query(int i,int j,int l,int r)
{
int d=tree[tree[j].l].sum-tree[tree[i].l].sum;
if(l==r)
return l;
int mid=l+r>>1;
if(d<(mid-l+1))
return query(tree[i].l,tree[j].l,l,mid);
else
return query(tree[i].r,tree[j].r,mid+1,r);
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int num;
scanf("%d",&num);
root[i]=root[i-1];
update(num+1,root[i],1,n);
}
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
if(l==1&&r==n)
printf("%d\n",n);
else
printf("%d\n",query(root[l-1],root[r],1,n)-1);
}
return 0;
}
思维
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
int mmin1[N],mmin2[N],a[N];
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
mmin1[0]=mmin2[n+1]=n;
for(int i=1;i<=n;i++)
mmin1[i]=min(mmin1[i-1],a[i]);
for(int i=n;i>=1;i--)
mmin2[i]=min(mmin2[i+1],a[i]);
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",min(mmin1[l-1],mmin2[r+1]));
}
return 0;
}