bzoj 3339 mex [线段树] [巧妙的方法] [离线处理]

mex(mex.cpp/c/pas)
【题目描述】
bzoj 3339 mex [线段树] [巧妙的方法] [离线处理]_第1张图片
【输入格式】
bzoj 3339 mex [线段树] [巧妙的方法] [离线处理]_第2张图片
【输出格式】
这里写图片描述
【样例输入】
7 5
0 2 1 0 1 3 2
1 3
2 3
1 4
3 6
2 7
【样例输出】
3
0
3
2
4
【样例解释与数据范围】

bzoj 3339 mex [线段树] [巧妙的方法] [离线处理]_第3张图片


这道题非常地巧妙!!
首先离线处理之后,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;
}

你可能感兴趣的:(数据结构,bzoj,线段树,离线处理)