2023 天梯赛 L2-3 锦标赛
这题主考一个实现,思路其实简单,因为是两两比较,那只需要一个个放就行了,放不了就是不行,赛后用线段树写了一下,丑丑的,勿怪()
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=3e5;//点最多有1<<18
struct tree{
int l,r,mx;
bool have;//下面的点有没有全填过
int mid(){
return (l+r)/2;
};
}tr[N<<2];
int a[N];//答案数组
bool flag=0,st;//flag判是否可行,st判是否在某轮填了数字
void up(int rt){//更新最大值和有没有填过
tr[rt].mx=max(tr[rt<<1].mx,tr[rt<<1|1].mx);
tr[rt].have=tr[rt<<1].have&&tr[rt<<1|1].have;
}
void build(int rt,int l,int r){//建树
tr[rt]={l,r};
if(l==r){
tr[rt].mx=a[l];
if(a[l]>0) tr[rt].have=1;
return;
}
int mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
up(rt);
}
void modify(int rt,int l,int r,int pos){
if(!st) return;//塞过了
if(tr[rt].have) return;//这个区间下面的点全部填过了
if(tr[rt].l>r || tr[rt].r<l) return;//不是要改的区间
if(tr[rt].l==l && tr[rt].r==r && tr[rt].mx>pos) return;//这个区间要的最大值给不起
//不合法的全去掉了
if(tr[rt].l==tr[rt].r){//到达底端
a[tr[rt].l]=pos;//直接改掉,输出的时候方便;
tr[rt].mx=pos;
tr[rt].have=1;
st=0;
return;
}
modify(rt<<1,l,r,pos);
modify(rt<<1|1,l,r,pos);
up(rt);
}
int main() {
int n;scanf("%d",&n);
for(int i=1;i<=(1<<n);i+=2){//第一轮直接放进去
scanf("%d",&a[i]);
}
build(1,1,(1<<n));
int add=4;//每次的间隔
//
for(int i=n-2;i>=0;i--){//差几轮
for(int j=1;j<=(1<<n);j+=add){//每轮填的数
int pos;scanf("%d",&pos);
if(flag) continue;//已经不可能了
int l=j,r=j+add-1;
int mid=l+r>>1;
st=1;//表示还没塞
modify(1,l,mid,pos);
if(st) modify(1,mid+1,r,pos);//前面不行
if(st) flag=1;//都不行
}
add*=2;//区间间隔增加
}
int pos;scanf("%d",&pos);//最后看胜者是不是最大
if(pos<=tr[1].mx) flag=1;
if(flag) printf("No Solution");
else{
for(int i=1;i<=(1<<n);i++){
if(a[i]) printf("%d ",a[i]);
else printf("%d ",pos);
}
}
return 0;
}