[??记录]AT2688 [ARC080C] Young Maids

command_block

2021-05-12 07:55:08

Personal

**题意** : 给定 $n$ 元排列 $p = (p_1, p_2, ..., p_n)$. (保证 $n$ 为偶数) 根据下述步骤构造一个 $N$ 元排列 $q$。 首先,令 $q$ 为空。接下来,执行下述操作直到 $p$ 为空。 - 选择 $p$ 中两个相邻元素 ,按原顺序设它们是 $x,y$. 从 $p$ 中移除 $x,y$,将它们按顺序接在 $q$ 的**前面**。 求可能的形成的字典序最小的 $q$ 。 $2\times 10^5$ ,时限$\texttt{2s}$。 ------------ 观察我们最终拿出的对子有什么特征,不难发现,对子形成一个括号序列,且要从里到外拿取。 考虑最后一步如何操作。 尝试寻找一个最小的,能作为最外层左括号的位置,不难发现只需下标是奇数就可以了。 接着寻找一个最小的,与之配对的右括号。这需要早左括号右边,且下标为偶数。 (这两步可以用线段树或 ST 表) 确定这一对括号之后,我们将序列分为了三部分 : ```cpp ...A... ( ...B... ) ...C... ``` 这三部分的对子选取顺序是互不干扰的,故按照子问题处理。 处理完成后,我们得到了配对方案,以及对子之间的先后顺序(形如外向树) 在这个外向树上用堆贪心求出最小拓扑序列即可。 复杂度 $O(n\log n)$。 ```cpp #include<algorithm> #include<cstdio> #include<queue> #define Pr pair<int,int> #define fir first #define sec second #define mp make_pair #define pb push_back #define MaxN 100500 using namespace std; int lg2[MaxN]; struct ST { Pr t[18][MaxN]; void Init(int *x,int n){ for (int i=1;i<=n;i++)t[0][i]=mp(x[i],i); for (int j=1;(1<<j)<=n;j++) for (int i=1;i+(1<<j)-1<=n;i++) t[j][i]=min(t[j-1][i],t[j-1][i+(1<<j-1)]); } Pr qry(int l,int r){ int k=lg2[r-l+1]; return min(t[k][l],t[k][r-(1<<k)+1]); } }T0,T1; Pr s[MaxN];int tn; vector<int> g[MaxN]; int solve(int l,int r) { int u=++tn; if (l&1){ Pr tl=T1.qry((l+1)/2,(r+1)/2), tr=T0.qry(tl.sec,r/2); s[u]=mp(-tl.fir,tr.fir); if (l<=tl.sec*2-2)g[u].pb(solve(l,tl.sec*2-2)); if (tl.sec*2<=tr.sec*2-1)g[u].pb(solve(tl.sec*2,tr.sec*2-1)); if (tr.sec*2+1<=r)g[u].pb(solve(tr.sec*2+1,r)); }else { Pr tl=T0.qry(l/2,r/2), tr=T1.qry(tl.sec+1,(r+1)/2); s[u]=mp(-tl.fir,tr.fir); if (l<=tl.sec*2-1)g[u].pb(solve(l,tl.sec*2-1)); if (tl.sec*2+1<=tr.sec*2-2)g[u].pb(solve(tl.sec*2+1,tr.sec*2-2)); if (tr.sec*2<=r)g[u].pb(solve(tr.sec*2,r)); }return u; } priority_queue< pair<Pr,int> >q; int n,x0[MaxN],x1[MaxN],ans[MaxN<<1]; int main() { scanf("%d",&n); for (int i=1;i<=n;i++) if (i&1)scanf("%d",&x1[i/2+1]); else scanf("%d",&x0[i/2]); T0.Init(x0,n/2);T1.Init(x1,n/2); lg2[1]=0;for (int i=2;i<=n/2;i++)lg2[i]=lg2[i>>1]+1; int rt=solve(1,n); q.push(mp(s[rt],rt)); tn=0; while(!q.empty()){ int u=q.top().sec;q.pop(); ans[++tn]=-s[u].fir;ans[++tn]=s[u].sec; for (int i=0;i<g[u].size();i++) q.push(mp(s[g[u][i]],g[u][i])); } for (int i=1;i<=tn;i++) printf("%d ",ans[i]); return 0; } ```