绝妙的平衡

3 篇文章 0 订阅
文章讲述了如何在给定的有根树中,对红色节点的子树进行权值赋值,使得每个红色节点的子树节点权值之和为3的倍数。作者通过深度优先搜索(DFS)的方法,找出以红色节点为根的子树并确定赋值策略。
摘要由CSDN通过智能技术生成

J-绝妙的平衡_2024牛客寒假算法基础集训营6 (nowcoder.com)

题目大意

小红拿到了一棵有根树,其中有一些节点被染成了红色。树的根节点是 1 号节点。
小红希望你给每个节点的权值赋值为 1 或者 2,需要满足每个红色节点的子树节点权值之和为 3 的倍数。
请你给出任意一个赋值方案。

思路

首先 全是红色不行 因为只能赋值 1 或 2 

那么在以一个红点为root的树中是什么样子呢?

假设先全部赋值为2

如果和取模后为1 比如只有两个点 (2+2)%3 = 1那么就让一个点变成1就好

2呢 就让那两个点变成1

所以只要满足至少有两个点 就可以满足情况

总结 我们需要做的就是找到所有以红点为root的子树遍历它有至少两个节点就可以了

代码

#include<iostream>
#include<cstdio>
#include<stack>
#include<vector>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#include<queue>
#include<set>
#include<vector>
#define int long long
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define  long long
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int INF = 1e18 + 10;
const int N = 1e5 + 10;
const int M = 1e7 + 10;// 节点数量 3e6就够了是为什么?
const int mod = 1e9 + 7;
int n, m, k, x;
int qcal(int a, int b) { int res = 1; while (b) { if (b & 1) res = res * a % mod; b >>= 1; a = a * a % mod; } return res; }
string st;
bool is_prime(int n) { if (n < 2) return false; for (int i = 2; i <= n / i; i++) { if (n % i == 0) { return false; } }return true; }
vector<vector<int>> a(N);
bool ans = true;
int res[N];

void dfs(int now)
{
    //需要统计这个以红为root的子树有多少个
    vector<int> all;
    all.push_back(now);
    //假如儿子还有很多儿子 我们就需要用一个queue来遍历每一个当前红root的儿子
    queue<int> q;
    for(auto c:a[now]) q.push(c);// 已经存了待用的点了
    // 现在的任务就是把他们遍历完
    while(!q.empty())
    {
        int tmp = q.front();
        q.pop();
        if(st[tmp] == 'R')
        {
            dfs(tmp);
            continue; // 遍历完就不需要遍历了 相当于删掉这颗子树
        }
        all.push_back(tmp);
        for(auto c:a[tmp]) q.push(c); //一定不能忘记往下遍历 倘若都是白的 应该再往下找 只要放进队列就行
    }  
    // 遍历完一棵以红节点为root的树之后我们需要检验
    if(all.size() < 2) 
    {
        ans = false;
        return;
    }
    // 然后把每个节点赋值
    if(all.size() % 2 == 1) 
    {
        // cout << "SIZE: " << all.size() << endl;
        res[all[0]] = res[all[1]] = res[all[2]] = 1; // 先让前三个点为1 因为至少有三个点 后面的12循环即可
        for(int i = 3;i < all.size();i ++)
        {
            if(i % 2) res[all[i]] = 1;
            else res[all[i]] = 2;
        }
    }
    else
    {
        for(int i = 0;i < all.size();i ++)
        {
            if(i % 2) res[all[i]] = 1;
            else res[all[i]] = 2;
        }
    }
}

void solve(int now)
{
    // 如果当前这个点是R就dfs 搞完就删除
    if(st[now] == 'R')
    {
        dfs(now);
    }
    // 如果不是 就把所有的儿子处理一下
    for(auto c:a[now]) solve(c);
}

void gzy()
{
    cin >> n >> st;
    st = " " + st;
    for(int i = 2;i <= n;i ++)
    {
        cin >> x;
        a[x].push_back(i);
    }
    solve(1); // 从第一个点开始遍历
    if(!ans) 
    {
        cout << -1 << endl;
        return;
    }
    // 对于一开始就是白色节点 他们暂时是没有被赋值的 所以需要全部让他们为一个值的
    for(int i = 1;i <= n;i ++) 
        if(!res[i]) res[i] = 1;
    for(int i = 1;i <= n;i ++) cout << res[i];
    puts("");
}

signed main()
{
    IOS;
    int _ = 1;
    while (_--) gzy();
    return 0;
}
// /**
//  *  ┏┓   ┏┓+ +
//  * ┏┛┻━━━┛┻┓ + +
//  * ┃       ┃
//  * ┃   ━   ┃ ++ + + +
//  *  ████━████+
//  *  ◥██◤ ◥██◤ +
//  * ┃   ┻   ┃
//  * ┃       ┃ + +
//  * ┗━┓   ┏━┛
//  *   ┃   ┃ + + + +Code is far away from  
//  *   ┃   ┃ + bug with the animal protecting
//  *   ┃    ┗━━━┓ 神兽保佑,代码无bug 
//  *   ┃  	    ┣┓
//  *    ┃        ┏┛
//  *     ┗┓┓┏━┳┓┏┛ + + + +
//  *    ┃┫┫ ┃┫┫
//  *    ┗┻┛ ┗┻┛+ + + +
//  */

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值