mex(mex.cpp/c/pas)
【题目描述】
【输入格式】
【输出格式】
【样例输入】
7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7
【样例输出】
3
0
3
2
4
【样例解释与数据范围】
这道题非常地巧妙!!
首先离线处理之后,mex() 就表示从 i 开始以后的 mex 值 , 然后由于固定 r 的 mex() 具有单调递减的性质,那么就可以从 [l,r] 转移到 [l+1,r] , 同时由于从 l+1 到 next[l]-1 都需要更新,那么就用线段树维护区间更新最小值就可以了,最后单点查询。。
注意更新和下方 lazy 时要采用更新最小的方式,而不能直接复制!!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
const int INF=0x3f3f3f3f;
const int maxn = 200005;
struct Query
{
int l,r;
int id;
int ans;
bool operator < (const Query t) const { return l < t.l; }
inline void read(int idx) { scanf("%d%d",&l,&r); id=idx; }
}que[maxn];
inline bool cmp(const Query a,const Query b) { return a.id < b.id; }
int a[maxn];
int n,q;
int next[maxn],last[maxn];
int mex0[maxn];
bool vis[maxn];
inline void init()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",a+i),last[a[i]]=n+1;
for(int i=1;i<=q;i++) que[i].read(i);
sort(que+1,que+q+1);
for(int i=n;i>=1;i--)
{
next[i] = last[a[i]];
last[a[i]] = i;
}
for(int i=1;i<=n;i++)
{
vis[a[i]]=true;
mex0[i]=mex0[i-1];
if(mex0[i]==a[i]) while(vis[mex0[i]]) mex0[i]++;
}
}
int mex[maxn<<2]; // mex value of [now,i]
int lazy[maxn<<2]; // -1 is set to hurdle , lazy of minimum value
void build(int root,int l,int r)
{
if(l==r)
{
mex[root]=mex0[l];
return;
}
int m=(l+r)>>1;
build(root<<1,l,m);
build(root<<1|1,m+1,r);
}
inline void pushdown(int root)
{
if(!~lazy[root]) return;
smin(mex[root<<1],lazy[root]);
if(!~lazy[root<<1]) lazy[root<<1]=lazy[root];
else smin(lazy[root<<1],lazy[root]);
smin(mex[root<<1|1],lazy[root]);
if(!~lazy[root<<1|1]) lazy[root<<1|1]=lazy[root];
else smin(lazy[root<<1|1],lazy[root]);
lazy[root]=-1;
}
void modify(int root,int l,int r,int x,int y,int val)
{
if(x<=l && r<=y)
{
smin(mex[root],val);
if(!~lazy[root]) lazy[root]=val;
else smin(lazy[root],val);
return;
}
pushdown(root);
int m=(l+r)>>1;
if(x<=m && l<=y) modify(root<<1,l,m,x,y,val);
if(y>=m+1 && r>=x) modify(root<<1|1,m+1,r,x,y,val);
}
int query(int root,int l,int r,int pos)
{
if(l==pos && pos==r) return mex[root];
pushdown(root);
int m=(l+r)>>1;
if(pos<=m) return query(root<<1,l,m,pos);
else return query(root<<1|1,m+1,r,pos);
}
void work()
{
memset(lazy,-1,sizeof(lazy));
build(1,1,n);
int pos=1; // for the queries
for(int i=1;i<=n;i++) // take turns to update segment tree
{
while(i == que[pos].l) que[pos].ans=query(1,1,n,que[pos].r) , pos++;
if(i1,1,n,i+1,next[i]-1,a[i]);
}
sort(que+1,que+q+1,cmp);
for(int i=1;iprintf("%d\n",que[i].ans);
printf("%d",que[q].ans);
}
int main()
{
freopen("mex.in","r",stdin);
freopen("mex.out","w",stdout);
init();
work();
return 0;
}