HDU 5764 After a Sleepless Night

Description

The yearly Multi-University Training Contest is coming, and ?? had already prepared an interesting and challenging problem for all those intelligent brains. However, when he told teammates about his “wonderful idea”, it really shocked him that all of them, except himself, had already seen an existing problem with the same trick.So he need to rack his brain again.
But nothing is difficult for a willing heart. After thinking about it all through the night, he came up with a new problem:
The original rooted tree has n nodes, numbered from 1 to n. Each node has a value, all of these values form a permutation of [1,n]. We reset these values by the following way:
new value(P) = max{previous value(Q)|Q is in the subtree with root P}
Given the new tree(each node’s number, it’s neighbors and it’s value), your job is to restore its original appearance.
Note that the root of the given tree is unspecified.

Solution

发现title放成HDU访问量会上升

比赛的时候想出来了好高兴!!!
在ShinFeb面前口胡AC好高兴!!!
当了一下领导好高兴

不知为何感觉这题神似省选Day1rzz讲课的最后题Andrew Stankevich Contest 24 E,当时就口胡AC了。。

那题的题意:
对于一个 1 n 的排列 a ,定义a/i为在该排列中去掉i后,剩下数相对大小和位置不变构成一个
1 n1 的排列。
(1,3,5,2,6,4)/2=(1,2,4,5,3)
所有1 in a/i 顺序打乱后给出。
要求还原一个合法的排列 a

觉得相似好像是因为都在找不变量?
首先这题根节点的权值一定是n对吧
然后权值为 n 的点会构成链对吧
根节点一定在这条链的一端对吧
直接用度判一下可以得到至多两个可以作为根的点
然后分开求val即可

当然求 val 的过程就不很无脑了。
要用字典序贪心。
当然也是很简单的
对于点 v ,它的子节点newvalue最大值是 mx
如果 A[v]>mx v 的权值可以确定了对吧
否则我们可以得到关于val[v]的约束信息: 1val[v]A[v]
为了满足字典序,从大到小枚举 val ,开个堆随便贪贪心即可

不能理解为何赛场上没什么人A这题

本地测试一直RE,后来想弃坑了,随手一交,莫名AC。。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vec;
typedef pair<int,int> pii;
#define pb push_back
#define ph push
#define fi first
#define se second
template<class T>void rd(T &a){
    a=0;char c;
    while(c=getchar(),!isdigit(c));
    do a=a*10+(c^48);
        while(c=getchar(),isdigit(c));
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar(48+x%10);
}
template<class T>void pt(T x){
    if(!x)putchar('0');
    else nt(x);
}
template<class T>void Max(T &a,T b){
    if(a<b)a=b;
}
template<class T>void Min(T &a,T b){
    if(a==-1||a>b)a=b;
}
const int M=1e5+5;
int A[M];
struct Edge{int to,nxt;}G[M<<1];
int head[M],tot_edge,txt;
inline void add_edge(int from,int to){
    G[tot_edge]=(Edge){to,head[from]};
    head[from]=tot_edge++;
}
int val[M],res[M],n;
bool mark[M],responsible;
inline void dfs(int v,int fa){
    if(!responsible)return;
    int Mx=0;
    for(int i=head[v];~i;i=G[i].nxt){
        int to=G[i].to;
        if(to==fa)continue;
        dfs(to,v);
        Max(Mx,A[to]);
    }
    if(A[v]>Mx)val[v]=A[v],mark[A[v]]=1;
    if(A[v]<Mx)responsible=0;
}
inline bool check(int rt){
    memset(val,0,sizeof(val));
    memset(mark,0,sizeof(mark));
    responsible=1;
    dfs(rt,rt);
    if(!responsible)return 0;
    priority_queue<pii>query;
    priority_queue<int>pque;
    for(int i=n;i;--i)
        if(!val[i])query.ph(pii(A[i],i));

    for(int i=n;i;--i){//color node
        if(mark[i])continue;
        for(pii now;!query.empty();){
            now=query.top();
            if(now.fi>=i)
                pque.ph(now.se),query.pop();
            else break;
        }
        if(pque.empty())return 0;
        int v=pque.top();pque.pop();
        val[v]=i;
    }
    return 1;
}
int que[M],top,RT[5],d[M];
inline void gao(){
    printf("Case #%d:",++txt);
    cin>>n;
    memset(d,0,sizeof(d));
    memset(head,-1,sizeof(head));
    top=tot_edge=0;
    for(int i=1;i<=n;++i){
        rd(A[i]);
        if(A[i]==n)que[++top]=i;
    }
    for(int i=1,a,b;i<n;++i){
        rd(a),rd(b);
        add_edge(a,b),add_edge(b,a);
        if(A[a]==n&&A[b]==n)++d[a],++d[b];
    }
    if(!top){puts(" Impossible");return;}
    int c=res[0]=0;
    if(top>1){
        for(int i=1;i<=top;++i){
            int v=que[i];
            if(d[v]==1)RT[++c]=v;
            if(d[v]>2||c>2||!d[v]){puts(" Impossible");return;}
        }
        if(c!=2){puts(" Impossible");return;}
    }
    else RT[++c]=que[1];
    if(!c){puts(" Impossible");return;}
    for(int i=1;i<=c;++i){
        int v=RT[i];
        bool flag=check(v);
        if(flag){
            if(!res[0])
                for(int i=1;i<=n;++i)
                    res[i]=val[i];
            else{
                bool f=0;
                for(int i=1;i<=n;++i){
                    if(val[i]>res[i])break;
                    if(val[i]<res[i]){f=1;break;}
                }
                if(f)for(int i=1;i<=n;++i)
                    res[i]=val[i];
            }
            res[0]=1;
        }
    }
    if(!res[0]){puts(" Impossible");return;}
    for(int i=1;i<=n;++i)
        putchar(' '),pt(res[i]);
    putchar('\n');
}
//#define LOCAL
int main(){
#ifdef LOCAL
    freopen("data.in","r",stdin);
    freopen("check.out","w",stdout);
#endif
    int _;
    for(cin>>_;_--;)gao();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值