Loading

6279. 2019.8.5【NOIP提高组A】优美序列

Description

Lxy 养了 N 头奶牛,他把 N 头奶牛用 1..N 编号,第 i 头奶牛编号 i 。为了让奶牛多产奶,每天早上他都会让奶牛们排成一排做早操。奶牛们是随机排列的。在奶牛排列中,如果一段区间 [L, R] 中的数从小到大排列后是连续的,他认为这段区间是优美的。比如奶牛排列为: (3,1,7,5,6,4,2),区间 [3,6] 是优美的,它包含 4,5,6,7 连续的四个数,而区间 [1,3] 是不优美的。Lxy 的问题是对于给定的一个区间 [L, R] (1<=L<=R<=N),他想知道,包含区间 [L,R] 的最短优美区间,比如区间 [1,3] 的最短优美区间是 [1,7]。

Solution

首先,两个相交的优美区间的交或并都是优美区间。

考虑什么情况下 \([L,R]\) 会是优美区间。

如果这 \(R-L+1\) 个数中有 \(R-L\) 对数值上的相邻关系,根据鸽巢原理,可以证明这个区间就是优美区间。

那么如何得到这个区间中有 \(R-L\) 对相邻关系呢?

\(val_i=i\),如果枚举到一个 \(R\)\(L\),满足 \(val_L=R\) 那么说明存在 \(R-L\) 对相邻关系。

为了更快的求出结果,考虑将询问离线。

将询问挂在右端点。枚举到右端点时,设 \(pos\) 表示与 \(a_i\) 相邻的数 的位置,区间 [1,pos] 加一,表示多了一对相邻关系。

随后将询问丢进优先队列(按照 \(L\) 从大到小的顺序),查询 [1,L] 中的最大值 \(v\),若 \(v=R\) 则答案就为最大值中最右侧的位置(线段树维护最大值和位置)。

Code

#include<queue>
#include<cstdio>
#include<vector>
#include<algorithm>
#define N 100005
using namespace std;
int n,m,x,y,ansl,ansr,a[N],p[N];
struct seq 
{
    int l,id;
    bool operator<(const seq &x) const
    {
        return l<x.l;
    }
};
struct seg {int val,pos,lz;}tr[N<<2];
struct sequn {int l,r;}ans[N];
vector<seq> q[N];
priority_queue<seq> qu;
void build(int x,int l,int r)
{
    if (l==r)
    {
        tr[x].pos=tr[x].val=l;
        return;
    }
    int mid=(l+r)>>1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    tr[x].val=max(tr[x<<1].val,tr[x<<1|1].val);
    tr[x].pos=tr[x<<1].val>tr[x<<1|1].val?tr[x<<1].pos:tr[x<<1|1].pos;
}
void pushdown(int x)
{
    if (tr[x].lz)
    {
        tr[x<<1].lz+=tr[x].lz;tr[x<<1].val+=tr[x].lz;
        tr[x<<1|1].lz+=tr[x].lz;tr[x<<1|1].val+=tr[x].lz;
        tr[x].lz=0;
    }
}
void modify(int x,int l,int r,int p,int q)
{
    if (p<=l&&q>=r)
    {
        tr[x].lz++;
        tr[x].val++;
        return;
    }
    pushdown(x);
    int mid=(l+r)>>1;
    if (mid>=p) modify(x<<1,l,mid,p,q);
    if (mid<q) modify(x<<1|1,mid+1,r,p,q);
    tr[x].val=max(tr[x<<1].val,tr[x<<1|1].val);
    tr[x].pos=tr[x<<1].val>tr[x<<1|1].val?tr[x<<1].pos:tr[x<<1|1].pos;
}
void query(int x,int l,int r,int p,int q)
{
    if (p<=l&&q>=r)
    {
        if (tr[x].val>=ansr) ansl=tr[x].pos,ansr=tr[x].val;
        return;
    }
    pushdown(x);
    int mid=(l+r)>>1;
    if (mid>=p) query(x<<1,l,mid,p,q);
    if (mid<q) query(x<<1|1,mid+1,r,p,q);
}
bool judge(seq x,int r)
{
    ansr=-1;
    query(1,1,n,1,x.l);
    if (ansr==r)
    {
        ans[x.id]=(sequn){ansl,ansr};
        return true;
    }
    return false;
}
int main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        scanf("%d",&a[i]),p[a[i]]=i;
    scanf("%d",&m);
    for (int i=1;i<=m;++i)
    {
        scanf("%d%d",&x,&y);
        q[y].push_back((seq){x,i});
    }
    build(1,1,n);
    for (int i=1;i<=n;++i)
    {
        if (a[i]>1&&p[a[i]-1]<=i) modify(1,1,n,1,p[a[i]-1]);
        if (a[i]<n&&p[a[i]+1]<=i) modify(1,1,n,1,p[a[i]+1]);
        for (int j=0;j<q[i].size();++j) qu.push(q[i][j]);
        while (!qu.empty())
        {
            if (judge(qu.top(),i)) qu.pop();
            else break;
        }
    }
    for (int i=1;i<=m;++i)
        printf("%d %d\n",ans[i].l,ans[i].r);
    return 0;
}
posted @ 2022-07-18 21:01  Thunder_S  阅读(42)  评论(0编辑  收藏  举报