题意:初始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; }
时间: 2024-11-05 09:09:30