[HDU5764] After a Sleepless Night [2016 Multi-University Training Contest 4(2016多校联合训练4) B]

来源:互联网 发布:cf淘宝刷枪是真的吗 编辑:程序博客网 时间:2024/04/28 11:49

比赛rank15,第一次这么靠前诶


题意

一棵节点数为n的树,树节点编号1n,每个节点也有一个权值1n,且互不相同。现用这棵树构建一棵新树,节点间连边不变,新图中每个节点的权值变为原图中该节点为根的子树中权值的最大值。
给出这棵新树的描述,问是否可以还原为原树?输出原图节点1n的权值,若有多种答案输出字典序最小的答案,无答案输出Impossible

题解

考虑原图变为新图后新图的性质。

  1. 权值n一定出现在新图中
  2. 新图中每种权值必然连成一条链
  3. 新图中从根开始向下遍历遇到的权值一定是非严格递减

于是这三条性质成为我们判断Impossible的一部分条件。

读入数据后先判定是否存在权值n。根据性质1

找到权值n所在的链,新树的根必然是这条链的两个端点之一。可以发现根的选择不影响其它链的上下方向及链之间的相对关系。而根的另一头一定填n,所以我们贪心地选择编号小的端点做根(否则交换两端点的值,会得到更优解)

下面从根开始dfs,遍历时记录一下father

遍历到一个节点u时:

如果u的权值和fa[u]相等,则chain[fa[u]]++,代表fa[u]的权值向下的分叉多了一个,当chain[fa[u]]>1时,根据性质2Impossible
如果u的权值大于fa[u]的权值,根据性质3Impossible

遍历u的儿子后返回

如果chain[u]=0说明u是它的权值的链中最靠下的点,它权值就是确定的了,即为当前的权值。

跳出dfs开始考虑填入剩下的权值。

n开始到1枚举权值:

如果当前权值已经被确定位置,即为某一条权值链的最下端,则取出这条权值链中其它节点的位置,存到一个大根堆中。注意这些位置对之后枚举的权值都是可行的位置,因为是从大到小枚举的权值。
如果当前权值未被确定位置,则从大根堆中取出堆顶,将此权值放入取出的位置上。这个地方是贪心使得字典序最小,若当前权值不使用这个最大的位置,通过交换当前权值和这个位置上的权值可以得到更优解。
如果当前权值未被确定位置,而堆空了,则Impossible

代码

// team646// by ztx// 2016-07-28 Multi University 1002#include <cstdio>#define Rep(i,l,r) for(i=(l);i<=(r);i++)#define rep(i,l,r) for(i=(l);i< (r);i++)#define Rev(i,r,l) for(i=(r);i>=(l);i--)#define rev(i,r,l) for(i=(r);i> (l);i--)typedef long long ll ;typedef double lf ;int CH , NEG ;template <typename TP>inline void read(TP& ret) {    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;    if (CH == '-') NEG = true , CH = getchar() ;    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;    if (NEG) ret = -ret ;}template <typename TP>inline void readc(TP& ret) {    while (ret=getchar() , ret<'!') ;    while (CH=getchar() , CH>'!') ;}template <typename TP>inline void reads(TP *ret) {    ret[0]=0;while (CH=getchar() , CH<'!') ;    while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;    ret[ret[0]+1]=0;}#include <algorithm>#include <queue>#define  maxn  100010LL#define  to(p)  e[0][p]#define  nxt(p) e[1][p]int e[2][maxn<<1],star[maxn],tote;inline void AddEdge(int u,int v) {    tote++;to(tote)=v;nxt(tote)=star[u];star[u]=tote;}std::priority_queue<int>heap;int n;int col[maxn], point[maxn], val[maxn];int chain[maxn], fa[maxn];bool ok;inline void dfs(int u) {    if (fa[u] && col[u] == col[fa[u]]) {        chain[fa[u]] ++ ;        if (chain[fa[u]] > 1) { ok = false ; return ; }    }    if (fa[u] && col[u] > col[fa[u]]) {        ok = false ; return ;    }    for (int p=star[u];p;p=nxt(p))        if (to(p)!=fa[u]) {            fa[to(p)] = u;            dfs(to(p)) ;            if (!ok) return ;        }    if (!chain[u]) {        point[col[u]] = u;        val[u] = col[u];    }}inline void work() {int i, j, u, v, root1, root2;    read(n);    tote = 0;    Rep (i,1,n)        point[i] = fa[i] = chain[i] = star[i] = 0;    Rep (i,1,n)        read(col[i]), point[col[i]] = i ;    rep (i,1,n) {        read(u) ,read(v) ;        AddEdge(u,v), AddEdge(v,u) ;    }    if (!point[n]) {        puts(" Impossible") ; return ;    }    i = point[n] ;    j = 0 ;    while (true) {        for (int p=star[i];p;p=nxt(p))            if (to(p)!=j && col[to(p)]==n)                {j=i,i=to(p); goto continue1;}        break ;        continue1:;    }    root1 = i; j = 0;    while (true) {        for (int p=star[i];p;p=nxt(p))            if (to(p)!=j && col[to(p)]==n)                {j=i,i=to(p);goto continue2;}        break;        continue2:;    }    root2 = i;    if (root1 > root2) root1^=root2,root2^=root1,root1^=root2;    ok = true ;    dfs(root1) ;    if (!ok) {        puts(" Impossible") ; return ;    }    while (!heap.empty()) heap.pop();    Rev (i,n,1)        if (point[i]) {            j = fa[point[i]];            while (j && col[j]==i) heap.push(j), j=fa[j];        } else {            if (heap.empty()) {                puts(" Impossible") ; return ;            }            j = heap.top(), heap.pop();            val[j] = i;        }    Rep (i,1,n)        printf(" %d",val[i]);    puts("");}int main() {int T, kiss;//    #define READ    #ifdef  READ        freopen(".in" ,"r",stdin ) ;        freopen(".out","w",stdout) ;    #endif    read(T) ;    Rep (kiss,1,T) {        printf("Case #%d:",kiss);        work() ;    }    #ifdef  READ        fclose(stdin) ; fclose(stdout) ;    #else        getchar() ; getchar() ;    #endif    return 0 ;}
1 0