正题
题目大意
nnn个点的一棵树,给每一个点一个权值,每个点的依靠点是与它相连的权值最小的点,要求每个点最多只有一个依赖点。
求字典序最小的方案
解题思路
首先最小的一定是叶子结点,然后他的父节点指向他,因为它是叶子,所以他也指向他的父节点。这样我们每次可以得到一个点对。
对于每个点对,连左边的点都比右边的点大,连右边的点都比左边的点大,这样我们就可以得到一张大小关系的有向图。求字典序最小的拓扑序即可
codecodecode
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=5e5+10;
priority_queue<int> q;
queue<int> p;
struct node{int to,next;
}a[N*2],e[N*2];
int n,in[N],ls[N],tot,w[N],rs[N],out[N],rest;
bool v[N];
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;in[y]++;return;
}
void adde(int x,int y){e[++tot].to=y;e[tot].next=rs[x];rs[x]=tot;out[y]++;return;
}
void combom(int x,int y){for(int i=ls[x];i;i=a[i].next){int z=a[i].to;if(z==y)continue;adde(y,z);in[z]--;if(in[z]==1)p.push(z);}for(int i=ls[y];i;i=a[i].next){int z=a[i].to;if(z==x)continue;adde(x,z);in[z]--;if(in[z]==1)p.push(z);}v[x]=v[y]=1;rest-=2;return;
}
void print(int x){if (x>9) print(x/10); putchar(x%10+48); return;
}
int main()
{scanf("%d",&n);if(n&1){printf("-1");return 0; }for(int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addl(x,y);addl(y,x); }tot=0;rest=n;for(int i=1;i<=n;i++)if(in[i]==1)p.push(i);for(int i=1;i<=n;i++){if(p.empty())break;int x=p.front();p.pop();if(v[x])continue;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(!v[y])combom(x,y);}}if(rest){printf("-1");return 0;}for(int i=1;i<=n;i++)if(!out[i])q.push(-i);while(!q.empty()){int x=-q.top();q.pop();print(x);putchar(' ');for(int i=rs[x];i;i=e[i].next){int y=e[i].to;out[y]--;if(out[y]==0)q.push(-y);}}return 0;
}