显然对于值为n的点一定构成链,然后我们只需要把两端最小的点作为根(为了字典序),然后就好办了,对于每棵子树根一定是最大值,然后最大值也一定形成链,这样我们就能把所有能确定的点确定下来(根的底端),然后不能确定的点的值一定小于等于输入的全值,下面介绍个人的处理方法:
我们从没有分配的最小的权值开始,因为字典序所以要分配给序号小的点,那么怎么办,我们可以先把所有未分配的店按输入的权值从小到大排序,对于每个点看看输入权值之前能分配多少个权值,如果分配个数大于这个点之前没有分配的点的数量,那么就能从这个点的后面取点扔到这个点的前面,用线段树维护即可。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn=100005;
vector<int>g[maxn];
int vis[maxn];
int use[maxn];
int a[maxn];
int in[maxn];
int ans[maxn];
int s[maxn];
int fa[maxn];
int find(int pa){
if(fa[pa]==-1||fa[pa]==pa) return fa[pa]=pa;
return fa[pa]=find(fa[pa]);
}
void init(int n){
for(int i=0;i<=n;i++){
vis[i]=0;
in[i]=0;
fa[i]=-1;
use[i]=0;
ans[i]=0;
g[i].clear();
}
}
int flag;
void dfs(int u,int pa){
int cnt=0;
for(int v:g[u]){
if(v!=pa){
if(a[v]>a[u]){
flag=1;
return;
}
if(a[v]==a[u]){
cnt++;
}
}
}
if(cnt>1){
flag=1;
return;
}
if(cnt==0){
ans[u]=a[u];
if(use[a[u]]){
flag=1;
return;
}
use[a[u]]=1;
}
for(int v:g[u]){
if(v!=pa)
dfs(v,u);
}
}
int x[maxn],y[maxn],to[maxn];
int cmp(int x,int y){
if(a[x]!=a[y]) return a[x]<a[y];
return x<y;
}
struct pi{
int le,ri;
int m1;
int m2;
int lazy;
}pp[maxn<<2];
void build(int tot,int l,int r){
pp[tot].le=l;
pp[tot].ri=r;
pp[tot].lazy=0;
if(l==r){
pp[tot].m1=x[l];
pp[tot].m2=s[a[x[l]]]-l;
return;
}
build(2*tot,l,(l+r)/2);
build(2*tot+1,(l+r)/2+1,r);
pp[tot].m1=min(pp[2*tot].m1,pp[2*tot+1].m1);
pp[tot].m2=min(pp[2*tot].m2,pp[2*tot+1].m2);
}
void merg1(int tot,int x){
if(pp[tot].le==pp[tot].ri){
pp[tot].m1=1000000000;
return;
}
int mid=(pp[tot].le+pp[tot].ri)/2;
if(x<=mid) merg1(2*tot,x);
else merg1(2*tot+1,x);
pp[tot].m1=min(pp[2*tot].m1,pp[2*tot+1].m1);
}
void merg2(int tot,int l,int r,int la){
if(l>r) return;
if(pp[tot].le>=l&&pp[tot].ri<=r){
pp[tot].lazy+=la;
return;
}
int mid=(pp[tot].le+pp[tot].ri)/2;
if(l<=mid) merg2(2*tot,l,r,la);
if(r>mid) merg2(2*tot+1,l,r,la);
pp[tot].m2=min(pp[2*tot].m2+pp[2*tot].lazy,pp[2*tot+1].m2+pp[2*tot+1].lazy);
}
int query(int tot,int all){
if(all+pp[tot].lazy+pp[tot].m2>0) return pp[tot].ri+1;
if(pp[tot].le==pp[tot].ri) return pp[tot].le;
all+=pp[tot].lazy;
int s= query(2*tot,all);
if(s<=pp[2*tot].ri) return s;
return query(2*tot+1,all);
}
int query1(int tot,int l,int r){
if(pp[tot].le>=l&&pp[tot].ri<=r) return pp[tot].m1;
int s=1000000000;
int mid=(pp[tot].le+pp[tot].ri)/2;
if(l<=mid) s=min(s,query1(2*tot,l,r));
if(r>mid) s=min(s,query1(2*tot+1,l,r));
return s;
}
int main()
{
int t,N=0;
cin>>t;
while(t--){
int n;
scanf("%d",&n);
init(n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
for(int i=1;i<=n;i++){
if(a[i]==n){
vis[i]=1;
}
}
for(int i=1;i<=n;i++){
if(!vis[i]) continue;
for(int v:g[i]){
if(vis[v]){
fa[find(i)]=find(v);
if(i<v){
in[i]++;
in[v]++;
}
}
}
}
int all=0;
flag=0;
for(int i=1;i<=n;i++){
if(vis[i]){
if(all==0){
all=find(i);
}
else{
if(all!=find(i)){
flag=1;
}
}
}
}
if(all==0) flag=1;
if(flag){
printf("Case #%d: Impossible\n",++N);
continue;
}
for(int i=1;i<=n;i++){
if(vis[i]){
if(in[i]>2){
flag=1;
}
}
}
if(flag){
printf("Case #%d: Impossible\n",++N);
continue;
}
int root=0;
for(int i=1;i<=n;i++){
if(vis[i]){
if(in[i]==1||in[i]==0){
root=i;
break;
}
}
}
dfs(root,-1);
if(flag){
printf("Case #%d: Impossible\n",++N);
continue;
}
int tot=0;
for(int i=1;i<=n;i++){
if(ans[i]==0) x[++tot]=i;
}
if(tot==0){
printf("Case #%d:",++N);
for(int i=1;i<=n;i++) printf(" %d",ans[i]);
printf("\n");
continue;
}
sort(x+1,x+tot+1,cmp);
tot=0;
for(int i=1;i<=n;i++){
s[i]=s[i-1];
if(use[i]==0){ y[++tot]=i;
s[i]++;
}
}
for(int i=1;i<=tot;i++){
if(s[a[x[i]]]<i){
flag=1;
break;
}
}
if(flag){
printf("Case #%d: Impossible\n",++N);
continue;
}
for(int i=1;i<=tot;i++) to[x[i]]=i;
build(1,1,tot);
for(int i=1;i<=tot;i++){
int w=query(1,0);
if(w>tot){
w=query1(1,1,tot);
ans[w]=y[i];
}
else{
int w1=query1(1,1,w);
ans[w1]=y[i];
w=w1;
}
merg1(1,to[w]);
merg2(1,1,to[w]-1,-1);
merg2(1,to[w],to[w],1000000000);
}
printf("Case #%d:",++N);
for(int i=1;i<=n;i++) printf(" %d",ans[i]);
printf("\n");
}
}