1. 程式人生 > >080E 思維+優先隊列維護

080E 思維+優先隊列維護

emp ++ col 維護 style inf std pac int

題意:初始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 思維+優先隊列維護