IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C. Tree Infection -> 正文阅读

[C++知识库]C. Tree Infection

https://codeforces.com/contest/1665/problem/C
在这里插入图片描述
input

5
7
1 1 1 2 2 4
5
5 5 1 4
2
1
3
3 1
6
1 1 1 1 1

output

4
4
2
3
4

在这里插入图片描述
题意
给定一颗树,循环 多次 先后 进行以下两步操作,询问最短花费多少时间使得树上每个节点都被染色

  1. 在每个父节点中,若其某个儿子倘若被染色了,则可以指定其另外 一个 儿子染色 (称为被动染色)
  2. 选择一个节点进行染色 (称为主动染色)

ps:假定一个父节点有四个儿子节点,且其中两个已经被染色,则经过一轮操作 1 1 1 ,最后变成三个儿子节点被染色,以及儿子节点并不会传染给父节点

思路

首先明确一点:儿子节点并不会传染给父节点,反过来父节点也不会传染给儿子,

如下图:
对于一堆有 t t t 个相同父节点的节点,假定一开始其中一个被染色并且我们不主动去染色,仅凭操作一它将会活动时间为 t ? 1 t - 1 t?1 便将这堆节点给染色完,之后便没有变化,且父节点没有变化

在这里插入图片描述
所以看出来每个父节点所对应的 子节点堆 都需要手动用操作 2 2 2 去染色

我们先将每个子节点堆取出来,然后根据贪心的思想,主动染色每次只能只能对一个点进行染色,而被动染色会发生在每个被染色过的堆中,所以最优的策略应该是对每个堆都 蜻蜓点水 ,让被动染色尽可能去消耗。但是主动染色是有个先后的过程,先染色的堆自然会被被动染色更多的点,而后染色的堆则会相对少一些

所以可以sort一下,先将数量大的堆先进行主动染色其中一个点,然后靠被动染色逐渐感染去消耗更多。

(如下图)
每列的高度表示每个堆的大小,绿色表示会被被动染色染色的过程(ps其中包含一个主动染色的块)
在这里插入图片描述

当我们将每个堆都染过一遍后,还有一些堆还剩余的怎么办?即上图中空白的块

因为我们知道染色的先后时间,所以可以计算出每个堆所剩多少个未染色的方块

这时候我们得用主动染色去帮助未完成的堆
因为每个情况比较复杂,以及题目所求的是最短时间,我这里便想到使用二分

即二分枚举剩下还会进行的时间

如何 c h e c k check check 枚举的 m i d mid mid 是否成立 ?
即: m i d mid mid 代表还会经过的时间,则表示可以主动染色 m i d mid mid 个位置 ,且被动染色也会在每一堆中消耗 m i d mid mid 个,所以每一堆剩下的数量减去 m i d > 0 mid > 0 mid0 ,则就表示我需要用主动染色去凑剩下的部分,所以对于每个堆统计一下需要主动染色的数量总和,再与 m i d mid mid 比较即可

AC代码
记得根节点也需要我们自己去染色

#include <algorithm>
#include <bits/stdc++.h>
#include <functional>
#include <vector>
#define endl '\n'
#define AC return 0;
using namespace std;
//#define ll long long
#define int long long

vector<int>v[200005];
vector<int>cnt;

void dfs(int p)
{
    if(v[p].size())
        cnt.push_back(v[p].size());
    for(auto i : v[p])
        dfs(i);

}

bool jud(int mid)
{
    int ti = mid;
    for(auto i : cnt)
    {
        if(i > mid)
            ti -= i - mid;
    }
    return ti >= 0;

}

void slove()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++)
        v[i].clear();
    cnt.clear();
    for(int i = 2; i <= n; i++)
    {
        int x;
        cin >> x;
        v[x].push_back(i);
    }    
    dfs(1);
    cnt.push_back(1);
    int sum = cnt.size();
    int k = 0;
    int ti = sum;
    sort(cnt.begin(),cnt.end(),greater<>());
    for(auto &i : cnt)
    {   
        i = max((int)0,i - ti);
        ti--;
    }
    // cout << sum << endl;
    int l = 0,r = 1e12;
    int ans;
    while(l <= r)
    {
        int mid = (l + r) >> 1;
        if(jud(mid))
        {
            ans = mid;
            r = mid - 1;
        }
        else
        {
            l = mid + 1;
        }
    }
    cout << sum + ans << endl;
}

signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T;cin >> T; while(T--)
    slove();
    AC
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-27 11:09:20  更:2022-04-27 11:09:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 20:40:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码