Codeforces Round #756 div3 D 有根树的权值分配 贪心 模拟

题目

给你N个节点的父节点Ai,当父节点和自己相同的时候就是根节点。
再你一个权值数组,要求节点到根的路的所有边加起来的权值dist,按权值数组的要求的大小关系存在。
当 P = 3,1,2,5,4 时 ,要求3节点最小,1节点第二小…以此类推。
要你提供一种合法的权值分配方案。即给每个节点到父节点的边赋值。
没有合法方案输出-1.

题解思路

树的题写的太少了,也挺怕这种题的。一开始就想什么dfs。

结果可以暴力的,我们按顺序给节点从小到大赋值即可。
儿子节点的值肯定比父节点大。所以他的顺序也必须在父节点后面。
我们直接考虑暴力,处理出每个节点到根节点的dist,其实也好处理,因为正确的顺序肯定是保证这个节点的父节点出现过的。
这样我们可以直接给这个节点的dist从小到大赋。
而这个节点的dist,就是赋的值减去父节点的dist。
这样赋值能保证dist只从0到n-1。

节点直接的关系一定要处理好。

AC代码
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long

using namespace std;

const  int  INF =  0x3f3f3f3f ;
const  int N = 200100 ;
int a[N] ; 
int dis[N] ; 
long long  valu[N] ; 
long long c[N] ; 

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T ; 
    cin >> T ;
    while ( T-- )
    {
        int n ;
        int root = -1 ; 
        cin >> n ; 
        for (int i = 1 ; i <= n ; i++ )
        {
            cin >> a[i] ;
            if (a[i] == i )
            {
                root = i ;
            }
        }
        for (int i = 1 ; i <= n ; i++ )
        {
            cin >> dis[i] ; 
            valu[i] = -1 ; 
        }
        if ( dis[1] == root )
        {
            int falg = 1 ;
            long long cnt = 1 ; 
            valu[root] = 0 ;
            c[root] = 0 ; 
            for (int i = 2 ; i <= n ; i++ )
            {
                int sp = dis[i] ; 
                if (valu[a[sp]] == -1 )
                {
                    falg = 0 ;
                    break ;
                }
                c[sp] = cnt++;
                valu[sp] = c[sp] -  c[a[sp]];
                //cout << sum << "\n" ; 
                //cout << dis[i] << " " << a[dis[i]] << "\n" ;
                //cout << valu[dis[i]] << " " << valu[a[dis[i]]] << "\n" ; 
            }
            if (falg)
            {
                //dfs(root,-1) ; 
                for (int i = 1 ; i <= n ; i++ )
                    cout << valu[i] << " ";
                cout << "\n" ; 
            }else
                cout << "-1\n" ; 
        }else
            cout << "-1\n" ;
    }
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值