Solution: 题解 CF1059E Split the Tree

给出一个堆贪心解法

记点\(u\)的深度为\(d_u(d_1=0)\),父亲为\(f_u\),拥有儿子数量\(es_u\)。

首先找到每个点的最远延伸点(点\(u\)的最远延伸点记为\(v_u\)),借助树上倍增即可。

接下来是贪心方法

在每次链连接完后删掉这些点,那么每条链的尾端一定是一个叶子。

那么就想办法找出目前贪心最优的叶子,然后往上连接。

以下的贪心本蒟蒻并没有想出严格证明方法,只能感性理解一下了QAQ。

贪心 1:目前\(d_{v_u}\)最小的叶子\(u\)是最优叶子

举个栗子:\(n=5,f_{2..n}=[1,1,2,2],v_{1..n}=[1,1,3,1,2]\)(请自行脑补这棵树)

现在的叶子有\(3,4,5\)。

因为\(3\)与其他叶子不冲突,所以直接考虑\(4,5\)即可。

如果选择\(4\),那么最多可以延伸出\(\{1,2,4\}\),剩下\(\{3\},\{5\}\),一共\(3\)条。

如果选择\(5\),那么最多只能延伸出\(\{2,5\}\),剩下的\(3,4\)不能帮忙带走\(1\),所以就\(4\)条了QAQ。

\(\therefore\) 应该选择\(d_{v_u}\)最小的叶子\(u\)以求带走更多的点。

贪心 2:对于最优叶子\(u\),能往上连就往上连

因为是目前最优的叶子,没有其他叶子可以到达\(v_u\),相比于让\(v_u\)重新开一条链,还是用\(u\)带走比较合算。

具体实现方法

构建一个存储点\(u\),以\(d_{v_u}\)为关键字的小根堆。

使用 dfs 求出\(v_u,es_u\),然后把叶子丢进堆里。

每次弹出一个点\(u\),答案计数\(+1\),并且往上连接,将路过的点用\(vs_u\)标记掉。

直到到达\(v_u\)或者该点已被标记,停止连接。

Particularly, 如果到达了\(v_u\)且没有被标记,那么\(f_{v_u}\)就失去了一个儿子,所以要处理\(es_{f_{v_u}}\)并判断入堆。

Time complexity: \(O(n\log n)\)

Memory complexity: \(O(n\log n)\)

具体见代码(\(823\)ms / \(49.40\)MB)

//This program is written by Brian Peng.
#pragma GCC optimize("Ofast","inline","no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Rd(a) (a=read())
#define Gc(a) (a=getchar())
#define Pc(a) putchar(a)
int read(){
    int x;char c(getchar());bool k;
    while(!isdigit(c)&&c^'-')if(Gc(c)==EOF)exit(0);
    if(c^'-')k=1,x=c&15;else k=x=0;
    while(isdigit(Gc(c)))x=(x<<1)+(x<<3)+(c&15);
    return k?x:-x;
}
void wr(int a){
    if(a<0)Pc('-'),a=-a;
    if(a<=9)Pc(a|'0');
    else wr(a/10),Pc((a%10)|'0');
}
signed const INF(0x3f3f3f3f),NINF(0xc3c3c3c3);
long long const LINF(0x3f3f3f3f3f3f3f3fLL),LNINF(0xc3c3c3c3c3c3c3c3LL);
#define Ps Pc(' ')
#define Pe Pc('\n')
#define Frn0(i,a,b) for(int i(a);i<(b);++i)
#define Frn1(i,a,b) for(int i(a);i<=(b);++i)
#define Frn_(i,a,b) for(int i(a);i>=(b);--i)
#define Mst(a,b) memset(a,b,sizeof(a))
#define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
#define N (100010)
int n,l,s,w[N],f[N][20],g[N][20],ans,d[N],es[N],lg[N]{-1},u,v[N];
bool vs[N];
vector<int>e[N];
struct Cmp{bool operator()(int a,int b)const{return d[v[a]]>d[v[b]];}};
priority_queue<int,vector<int>,Cmp>q;
void dfs(int u);
signed main(){
    Rd(n),Rd(l),Rd(s);
    Frn1(i,1,n)if(Rd(w[i])>s)wr(-1),exit(0);
    Frn1(i,2,n)e[Rd(*f[i])].push_back(i),lg[i]=lg[i>>1]+1;
    dfs(1);
    while(!q.empty()){
        u=q.top(),q.pop(),++ans;
        for(int p(u);!vs[p];p=*f[p]){
            vs[p]=1;
            if(p==v[u]){if(!--es[*f[v[u]]])q.push(*f[v[u]]);break;}
        }
    }
    wr(ans),exit(0);
}
void dfs(int u){
    Frn1(i,1,lg[d[u]])f[u][i]=f[f[u][i-1]][i-1],
        g[u][i]=g[u][i-1]+g[f[u][i-1]][i-1];
    int rs(s-w[v[u]=u]);
    Frn_(i,lg[d[u]],0)if(d[u]-d[v[u]]+(1<<i)<l&&g[v[u]][i]<=rs)
        rs-=g[v[u]][i],i=min(i,d[v[u]=f[v[u]][i]]);
    for(int i:e[u])*f[i]=u,*g[i]=w[u],d[i]=d[u]+1,dfs(i);
    if(!(es[u]=e[u].size()))q.push(u);
}

原文地址:https://www.cnblogs.com/BrianPeng/p/12340976.html

时间: 2024-11-08 20:59:08

Solution: 题解 CF1059E Split the Tree的相关文章

CF 1039D You Are Given a Tree &amp;&amp; CF1059E Split the Tree 的贪心解法

1039D 题意: 给你一棵树,要求对给定链长于 k = 1, 2, 3, ..., n,求出最大的链剖分. 1059E 题意: 给你一棵带权树,要求对于一组给定的 L, W 求出最小完全竖链剖分满足每条链点数不超过 L,权值和不超过 W. 显然两题是有共同点的,就是让我们求满足一定条件的树的最值链剖分. 比较暴力的可以尝试用 DP 计数,但是我不想深入 DP,因为方程比较复杂,思考起来不太容易. 很巧的是,这两题可以用相似的贪心思想来做. 在思考具体细节之前,需要明确贪心的主要思想:在从下往上

leetcode题解:Construct Binary Tree from Inorder and Postorder Traversal(根据中序和后序遍历构造二叉树)

题目: Given inorder and postorder traversal of a tree, construct the binary tree. Note:You may assume that duplicates do not exist in the tree. 说明: 1)实现与根据先序和中序遍历构造二叉树相似,题目参考请进 算法思想 中序序列:C.B.E.D.F.A.H.G.J.I 后序序列:C.E.F.D.B.H.J.I.G.A 递归思路: 根据后序遍历的特点,知道后序

[LeetCode 题解]: Validate Binary Search Tree

Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as follows: The left subtree of a node contains only nodes with keys less than the node's key. The right subtree of a node contains only nodes with keys

Split The Tree

Split The Tree 时间限制: 1 Sec  内存限制: 128 MB 题目描述 You are given a tree with n vertices, numbered from 1 to n. ith vertex has a value wiWe define the weight of a tree as the number of different vertex value in the tree.If we delete one edge in the tree, t

Lintcode7 Binary Tree Serialization solution 题解

[题目描述] Design an algorithm and write code to serialize and deserialize a binary tree. Writing the tree to a file is called 'serialization' and reading back from the file to reconstruct the exact same binary tree is 'deserialization'. 设计一个算法,并编写代码来序列化

Lintcode11 Search Range in Binary Search Tree solution 题解

[题目描述] Given two values k1 and k2 (where k1 < k2) and a root pointer to a Binary Search Tree. Find all the keys of tree in range k1 to k2. i.e. print all x such that k1<=x<=k2 and x is a key of given BST. Return all the keys in ascending order. 给

Lintcode70 Binary Tree Level Order Traversal II solution 题解

[题目描述] Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root). 给出一棵二叉树,返回其节点值从底向上的层次序遍历(按从叶节点所在层到根节点所在的层遍历,然后逐层从左往右遍历) [题目链接] www.lintcode.com/en/problem/binary

Lintcode202 Segment Tree Query solution 题解

[题目描述] For an integer array (index from 0 to n-1, where n is the size of this array), in the corresponding Segment Tree, each node stores an extra attribute max to denote the maximum number in the interval of the array (index from start to end). 对于一个

Lintcode203 Segment Tree Modify solution 题解

[题目描述] For a Maximum Segment Tree, which each node has an extra value max to store the maximum value in this node's interval. Implement a modify function with three parameter root,index and value to change the node's value with[start, end] = [index,