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;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

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

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

BZOJ3339: Rmq Problem 线段树

3339: Rmq Problem Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 1004  Solved: 507 [Submit][Stat...

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 4540] [Hnoi2016]序列:离线,线段树,矩阵乘法

题意:给一个长为N的序列,每项绝对值不超过10^9。Q个询问,求某区间的所有子区间的最小值之和。(1 ≤N,Q ≤ 100000) UPDATE 2017.5.27: 这类离线线段树问题更好的理解方式...

[BZOJ3585]mex(离线+离散化+线段树)

不要企图活的那么明白 不要哭泣 因为你是对的 不要用假话或恐惧拭干泪水 那样最终你会厌恶自己

BZOJ 2743 [HEOI2012]采花 离线+线段树

BZOJ 2743 [HEOI2012]采花 离线+线段树

[BZOJ4771][七彩树][可持久化线段树在线转离线+LCA+Set]

[BZOJ4771][七彩树][主席树+LCA+Set]题目大意:给定一棵N<=100000N<=100000个节点的有根树和M<=100000M(x⊕lastans,y⊕lastans)(x,y) ...

bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)

Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共...

BZOJ 3626 离线+树链剖分+线段树

思路: 抄一波yousiki的… 显然,暴力求解的复杂度是无法承受的。 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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