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);
	}
}
posted @ 2022-06-28 09:45  Prean  阅读(20)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};