首页 > 代码库 > 080E 思维+优先队列维护

080E 思维+优先队列维护

题意:初始q为空,给出排列p,每次取p中两个相邻的元素插入到q的开头,问q能得到的最小字典序为?
n<=2e5.
开头尽量小,假设最后一次取出的元素位置为[i,j].
则ij之间有偶数个元素,i前面有偶数个元素,j类似.i,j奇偶性相反.
i必须在某个奇数位置上,j必须在某个偶数位置上,RMQ维护奇/偶位置上的最小值
每次取出一个v1以后,查询v1后面的奇/偶性相反的最小值.
线段被分为三段[1,i),(i,j),(j,n] 把子线段加入到优先队列中(key为该线段左端点开始偶数位置中的最小值) O(nlogn).

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=2e5+20;
int mn[2][N][30],n,a[2][N],pos[N];
void init(int v)
{
    for(int i=0;i<n;i++)
        mn[v][i][0]=a[v][i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=0;(i+(1<<j)-1)<n;i++)
            mn[v][i][j]=min(mn[v][i][j-1],mn[v][i+(1<<(j-1))][j-1]);
}
int rmq(int l,int r,int v)
{
    int k=0;
    while((1<<(k+1))<=r-l+1)
        k++;
    return min(mn[v][l][k],mn[v][r-(1<<k)+1][k]);
}
struct node{
    int x,l,r;
    bool operator < (const node &t)const{
        return x>t.x;
    }
};
int main()
{
    int x;
    while(cin>>n)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            pos[x]=i;
            a[i&1][i]=x;
            a[(i&1)^1][i]=inf;
        }
        init(0),init(1);
        priority_queue<node> q;
        x=rmq(0,n-1,0);
        q.push({x,0,n-1});
        while(!q.empty())
        {
            node x=q.top();
            q.pop();
            int v1=x.x,v2=rmq(pos[x.x]+1,x.r,(pos[x.x]&1)^1);
            printf("%d %d ",v1,v2);
            v1=pos[v1],v2=pos[v2];
            if(x.l!=v1)
                q.push({rmq(x.l,v1-1,x.l&1),x.l,v1-1});
            if(v1+1!=v2)
                q.push({rmq(v1+1,v2-1,(v1+1)&1),v1+1,v2-1});
            if(v2!=x.r)
                q.push({rmq(v2+1,x.r,(v2+1)&1),v2+1,x.r});
        }
        printf("\n");
    }
    return 0;
 
} 

 

080E 思维+优先队列维护