bzoj 3339 Rmq problem 离线+线段树

原创 2017年01月03日 19:13:08

首先可以在O(n)的时间内求出1~i(for i 1~n)的答案ans[ i ]。然后对于l~r的答案与l+1~r答案的关系,把i~nxt[ i ]-1的所有大于a[i]的ans都改为a[i]就可以了,nxt[ i ]表示下一个最近的 值也是a[i]的位置。询问排一下序。

#include<cstdio>
#include<iostream>
#include<algorithm>
#define maxn 200005
using namespace std;
void read(int &a)
{
    a=0;char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')
    {
        a*=10;a+=c-'0';
        c=getchar();
    }
}
struct Que{
    int l,r;
    int id,ans;
}q[maxn];
bool cmp(Que A,Que B)
{return A.l<B.l;}
bool cmp2(Que A,Que B)
{return A.id<B.id;}
int a[maxn];
bool use[maxn];
int ans[maxn];
struct XDS{
    struct xds
    {
        int l,r;
        int add;
    }tree[maxn<<2];
    void build(int x,int l,int r)
    {
        tree[x].l=l;
        tree[x].r=r;
        tree[x].add=maxn;
        if(l==r) return ;
        int mid=(l+r)>>1;
        build(x<<1,l,mid);
        build(x<<1|1,mid+1,r);
    }
    void spread(int x)
    {
        tree[x<<1].add=min(tree[x].add,tree[x<<1].add);
        tree[x<<1|1].add=min(tree[x].add,tree[x<<1|1].add);
    }
    int L,R;
    void change(int x,int d)
    {
        if(tree[x].l>=L&&tree[x].r<=R)
        {
            tree[x].add=min(tree[x].add,d);
            return ;
        }
        spread(x);
        int mid=(tree[x].l+tree[x].r)>>1;
        if(mid>=L) change(x<<1,d);
        if(mid<R)  change(x<<1|1,d);
    }
    int ask(int x)
    {
        if(tree[x].l==L&&tree[x].r==R)
            return min(ans[L],tree[x].add);
        spread(x);
        int mid=(tree[x].l+tree[x].r)>>1;
        if(mid>=L) return ask(x<<1);
        return ask(x<<1|1);
    }
}TR;
int fst[maxn],nxt[maxn];
int main()
{
    int n,m,Max=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        read(a[i]);
        Max=max(Max,a[i]);
    }
    for(int i=0;i<=Max;i++)
        fst[i]=n+1;
    for(int i=n;i>=1;i--)
    {
        nxt[i]=fst[a[i]];
        fst[a[i]]=i;
    }
    for(int i=1;i<=n;i++)
    {
        use[a[i]]=1;
        int A=ans[i-1];
        while(use[A]) A++;
        ans[i]=A;
    }
    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);
    TR.build(1,1,n);
    int H=1;
    for(int i=1;i<=n;i++)
    {
        while(q[H].l==i)
        {
            TR.R=TR.L=q[H].r;
            q[H].ans=TR.ask(1);
            H++;
        }
        TR.L=i,TR.R=nxt[i]-1;
        TR.change(1,a[i]);
    }
    sort(q+1,q+m+1,cmp2);
    for(int i=1;i<=m;i++)
        printf("%d\n",q[i].ans);
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

BZOJ 3339 Rmq Problem【离线,值域线段树

区间mex,考虑离线按左端点排序 左端点右移时,这个数到它的下一个数之间的位置(作为右端点)的mex值全部与当前数取min #include #define MAXN 200005 #define M...
  • Flaze_
  • Flaze_
  • 2016年11月15日 14:45
  • 187

[BZOJ3339]Rmq Problem(离线+线段树)

膝盖还在发抖,如同十二岁时的我 从教室后门偷溜出去 我不在乎被责备两次 等待对我这种人来说是浪费时间...

BZOJ3339: Rmq Problem 线段树

3339: Rmq Problem Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1004  Solved: 507 [Submit][Stat...
  • Oakley_
  • Oakley_
  • 2016年10月12日 22:53
  • 163

bzoj 3339 线段树离线处理

题意:给定一个n个数的序列,多次询问,每次询问区间[l,r]的mex 直接暴力显然不可 区间[l,r]和区间[l',r']mex的情况: (1)[l,r]和[l',r']的mex值不同:[l,r...

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

mex(mex.cpp/c/pas) 【题目描述】 【输入格式】 【输出格式】 【样例输入】 7 5 0 2 1 0 1 3 2 1 3 2 3 1 4 3 6 ...

bzoj 3489: A simple rmq problem 可持久化线段树套可持久化线段树

题意给出n个数,每个数为[1,n],有m个询问,每次询问[l,r]内最大的只出现过一次的数。强制在线。 n...

[bzoj3339]mex(线段树)

白日落,渐晚些,半盏屠苏,诙谐曼倩取自容

【BZOJ3339】Rmq Problem

Description Input Output Sample Input 7 5 0 2 1 0 1 3 2 1 3 2 3 1 4 3 6 2 7 Sample ...

[BZOJ3585&3339][Rmq Problem][莫队+二分+树状数组]

[BZOJ3585&3339][Rmq Problem][莫队+二分+树状数组]题目大意:有一个长度为n的数组{a1,a2,…,an}。m次询问,每次询问一个区间内最小没有出现过的自然数。思路:先把所...
  • g1n0st
  • g1n0st
  • 2017年03月29日 18:58
  • 124

BZOJ 3339/3585 Rmq Problem/mex 莫队算法

连线段树都不愿意打了。。明明线段树要短 至于区间转移 如果是新增一个数字,和当前维护的mex值比较,如果相等,即已经把最小缺失的数字补上了,因此暴力查找下一个数字。其实想想写个树状数组应该也可?带...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj 3339 Rmq problem 离线+线段树
举报原因:
原因补充:

(最多只允许输入30个字)