AtCoder 2688 Young Maids

题目描述

Let N be a positive even number.
We have a permutation of (1,2,…,N), p=(p1,p2,…,pN). Snuke is constructing another permutation of (1,2,…,N), q, following the procedure below.
First, let q be an empty sequence. Then, perform the following operation until p becomes empty:
Select two adjacent elements in p, and call them x and y in order. Remove x and y from p (reducing the length of p by 2), and insert x and y, preserving the original order, at the beginning of q.
When p becomes empty, q will be a permutation of (1,2,…,N).
Find the lexicographically smallest permutation that can be obtained as q.

Constraints
N is an even number.
2≤N≤2×105
p is a permutation of (1,2,…,N).

输入

Input is given from Standard Input in the following format:
N
p1 p2 … pN

输出

Print the lexicographically smallest permutation, with spaces in between.

样例输入

4
3 2 4 1

样例输出

3 1 2 4

提示

The solution above is obtained as follows:

题目大意:

给出一个序列每次拿出相邻的两个放在另一个序列的开头,并且保证 拿出来的两个数相对位置不变(即左右不变)。

比赛的时候没有做出来,关键在于不知道怎么去去除已经查询过的数字。

我的想法是将奇数位和偶数位排序,然后依次取出一个奇数位最小的然后从奇数位在序列中的位置后边取出一个最小的

这样可以用线段树或者ST表,但是已经取出来的数字会对后边的造成影响,于是就。。。

参考了大牛的博客:

解法是用贪心的做法,从前往后取,每次取出来的两个数的位置的奇偶性一定是相反的,而且取出来的第一个数与区间左端点奇偶性相同,第二个数与区间右端点奇偶性相同。取出两个数后把区间分成了三部分。

然后分别将三个区间内的2个数的最小值求出,和区间端点一起放到一个优先队列里。

(优先队列以第一个数升序排列,因为第一个数越小字典序就相对越小)。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define N 200005
#define inf 0x3f3f3f3f
 
int t[N*4][2];
int a[N];
int ans[N];
 
struct node
{
    int l,r,u,v;
    friend bool operator <(node x,node y)
    {
        return a[x.u]>a[y.u];
    }
};
 
int Min(int x,int y)
{
    return a[x]<a[y]?x:y;
}
 
void pushup(int rt)
{
    t[rt][0]=Min(t[rt<<1][0],t[rt<<1|1][0]);
    t[rt][1]=Min(t[rt<<1][1],t[rt<<1|1][1]);
}
 
void build(int rt,int l,int r)
{
    if(l==r)
    {
        t[rt][l%2]=l;
        return ;
    }
    int m=(l+r)/2;
    build(rt*2,l,m);
    build(rt*2+1,m+1,r);
    pushup(rt);
}
 
int query(int rt,int l,int r,int ql,int qr,int f)
{
    //cout<<l<<"++"<<r<<ql<<" "<<qr<<endl;
    if(l>=ql && r<=qr)
    {
       // cout<<a[t[rt][f]]<<endl;
        return t[rt][f];
 
    }
    if(ql>r || qr<l)return 0;
    int m = (l+r)>>1;
    int q1=0,q2=0;
    q1=query(rt*2,l,m,ql,qr,f);
    q2=query(rt*2+1,m+1,r,ql,qr,f);
    return Min(q1,q2);
}
int n;
priority_queue<node>q;
 
void Print(int n)
{
    for(int i=1;i<n;i++)
    {
        printf("%d",ans[i]);
        if(i==n-1)printf("\n");
        else printf(" ");
    }
}
 
void ins(int l,int r)
{
    int u=query(1,1,n,l,r,l%2);
    int v=query(1,1,n,u+1,r,!(l%2));
    node tm;
    tm.l=l,tm.r=r;
    tm.u=u,tm.v=v;
    q.push(tm);
}
int main()
{
    while(cin>>n)
    {
        a[0]=inf;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        build(1,1,n);
        int cnt=1;
        node tem;
        ins(1,n);
        q.push(tem);
        while(!q.empty())
        {
            node t1=q.top();
            q.pop();
            int u=query(1,1,n,t1.u,t1.v,t1.u%2);
            //cout<<"t1.u="<<t1.u<<" t1.v"<<t1.v<<endl;
            int v=query(1,1,n,u+1,t1.v,!(t1.u%2));
            //cout<<" u="<<u+1<<" t1.v"<<t1.v<<endl;
            ans[cnt++]=a[u];
            ans[cnt++]=a[v];
            if(u-1>t1.l)ins(t1.l,u-1);
            if(u+1<v-1) ins(u+1,v-1);
            if(v+1<t1.r)ins(v+1,t1.r);
        }
        Print(cnt);
    }
}

参考博客:https://blog.csdn.net/WerKeyTom_FTD/article/details/78431182

猜你喜欢

转载自blog.csdn.net/weixin_40894017/article/details/81176107