ARC080E题解
考虑从前往后做,因为字典序是从前往后的,从后往前多少有点不现实。
可以发现这样子会有一个类似括号树的东西。我们递归把这棵树建出来,然后在上面跑堆+dfs即可。
建树只需要找到某个区域中下标为奇/偶数的最小值即可。
如果脑袋不太清醒建议别写这题(
#include<cstdio>
#include<queue>
const int M=2e5+5;
int n,m,ege,tot,h[M],a[M],w1[M],w2[M],mi[2][M<<2];
struct cmp{
inline bool operator()(const int&u,const int&v)const{
return w1[u]>w1[v];
}
};std::priority_queue<int,std::vector<int>,cmp>q;
struct Edge{
int v,nx;
}e[M];
inline int Getid(const int&id){
return id+(id&1)>>1;
}
inline int Min(const int&a,const int&b){
return::a[a]>::a[b]&&b||!a?b:a;
}
inline void Add(const int&u,const int&v){
e[++ege]=(Edge){v,h[u]};h[u]=ege;
}
inline void Build(const int&u,const int&L=1,const int&R=m){
if(L==R)return mi[1][u]=L*2-1,mi[0][u]=L*2,void();
const int&mid=L+R>>1;Build(u<<1,L,mid);Build(u<<1|1,mid+1,R);
mi[0][u]=Min(mi[0][u<<1],mi[0][u<<1|1]);mi[1][u]=Min(mi[1][u<<1],mi[1][u<<1|1]);
}
inline int Getmi(const int&u,const int&l,const int&r,const bool&typ,const int&L=1,const int&R=m){
if(l>R||L>r)return 0;if(l<=L&&R<=r)return mi[typ][u];
const int&mid=L+R>>1;return Min(Getmi(u<<1,l,r,typ,L,mid),Getmi(u<<1|1,l,r,typ,mid+1,R));
}
inline void Mdf(const int&u,const int&x,const bool&typ,const int&L=1,const int&R=m){
if(L==R)return mi[typ][u]=0,void();const int&mid=L+R>>1;
x<=mid?Mdf(u<<1,x,typ,L,mid):Mdf(u<<1|1,x,typ,mid+1,R);mi[typ][u]=Min(mi[typ][u<<1],mi[typ][u<<1|1]);
}
inline void Solve(const int u,const int&L,const int&R){
int x=Getmi(1,Getid(L),Getid(R-1),L&1),y=Getmi(1,Getid(x+1),Getid(R),R&1);
w1[u]=a[x];w2[u]=a[y];Mdf(1,Getid(x),x&1);Mdf(1,Getid(y),y&1);
if(x+1!=y)Add(u,++tot),Solve(tot,x+1,y-1);
if(x!=L)Add(u,++tot),Solve(tot,L,x-1);
if(y!=R)Add(u,++tot),Solve(tot,y+1,R);
}
signed main(){
scanf("%d",&n);m=n>>1;for(int i=1;i<=n;++i)scanf("%d",a+i);Build(1);Solve(++tot,1,n);q.push(1);
while(!q.empty()){
const int u=q.top();q.pop();printf("%d %d ",w1[u],w2[u]);
for(int E=h[u];E;E=e[E].nx)q.push(e[E].v);
}
}