首页 > 编程语言 >P9304 「DTOI-5」3-1题解,c++树的遍历例题

P9304 「DTOI-5」3-1题解,c++树的遍历例题

时间:2024-07-26 10:27:45浏览次数:19  
标签:ansi int 题解 ans deep leq deepest P9304 例题

题意

给定以 n ( 1 ≤ n ≤ 1 0 5 ) n(1 \leq n \leq 10^5) n(1≤n≤105) 个节点的树,根节点为 1 1 1。对于每个节点共有一下两种边与其相连:

  • 1 ≤ i , j ≤ n 1 \leq i,j \leq n 1≤i,j≤n,代表花费 1 1 1 个费用从 i i i 走到 j j j,无使用次数限制,共 n − 1 n - 1 n−1 条。
  • 2 ≤ i ≤ n 2 \leq i \leq n 2≤i≤n,代表花费 0 0 0 个费用从 i i i 走到 1 1 1,只能用不超过 1 1 1 次

要求输出访问 1 − n 1-n 1−n 个节点最少需要花费多少费用。

思路

考虑 n n n 个节点的费用,即这道题

在这里插入图片描述

首先,如果我们每个点都必须遍历一遍,再返回 1 1 1,那么总费用必定是 2 × ( n − 1 ) 2 \times (n - 1) 2×(n−1),因为每条边都必须走两遍。

对于传送操作,和 CF61D 类似,只需要删除一个最长边,就可以让操作数最小,总花费为 2 × ( n − 1 ) − d e e p e s t 2 \times (n - 1) - deepest 2×(n−1)−deepest, d e e p e s t deepest deepest 表示最长边长度。

从 n n n 反向考虑删点,第 i i i 个节点花费为 2 × ( i − 1 ) − d e e p e s t 2 \times (i - 1) - deepest 2×(i−1)−deepest, d e e p e s t deepest deepest 表示当前最长边长度。如果还有不在最长链上的点可以删除,则 a n s i = a n s i + 1 − 2 ans_i = ans_{i + 1} - 2 ansi​=ansi+1​−2,否则因为每次 d e e p e s t ← d e e p e s t − 1 deepest \gets deepest - 1 deepest←deepest−1,因此 a n s i = a n s i + 1 − 1 ans_i = ans_{i + 1} - 1 ansi​=ansi+1​−1,如果用从 1 1 1 正推的话,公式如下:

a n s i = { a n s i − 1 + 1 x ≤ d e e p e s t + 1 a n s i − 1 + 2 d e e p e s t ≤ x ≤ n ans_i = \begin{cases} ans_{i -1} + 1 & x \leq deepest + 1 \\ ans_{i - 1} + 2 & deepest \leq x \leq n \end{cases} ansi​={ansi−1​+1ansi−1​+2​x≤deepest+1deepest≤x≤n​

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n; 
int head[100005],nex[200005],to[200005],cnt = 0,a[200005];
void add(int x,int y) {
	nex[++cnt] = head[x];
	head[x] = cnt;
	to[cnt] = y;
}
int deep[100005],ans = -1e18;
void find_deep(int now,int fa) {
	for(int i = head[now];i;i = nex[i]) {
		if(to[i] != fa) {
			deep[to[i]] = deep[now] + 1;
			find_deep(to[i],now);
		} 
	}
	return;
}
signed main() {
	scanf("%lld",&n);
	for(int i = 1;i < n;i++) {
		int x,y;
		scanf("%lld %lld",&x,&y);
		add(x,y),add(y,x);
	}
	find_deep(1,1);
	for(int i = 1;i <= n;i++) ans = max(ans,deep[i]);
	for(int i = 1;i <= ans;i++) a[i] = a[i - 1] + 1;
	for(int i = ans + 1;i < n;i++) a[i] = a[i - 1] + 2;
	for(int i = 0;i < n;i++) printf("%lld\n",a[i]);
    return 0;
}


标签:ansi,int,题解,ans,deep,leq,deepest,P9304,例题
From: https://blog.csdn.net/guozhetao/article/details/140707998

相关文章

  • 题解:P10570 [JRKSJ R8] 网球(未成功)
    题目链接博客食用更佳:Myblog。这道题不是很难。提交记录分析:\(A\)每转\(a\)圈,\(B\)就转\(b\)圈,不考虑\(c\)的前提下,可知每个齿轮转了\([a,b]\)个齿,\(A\)有\([a,b]\diva\)个齿,\(B\)有\([a,b]\divb\)个齿,接着扩倍扩到都大于\(c\)。拓展:\[[a,b]=......
  • 题解:P10721 [GESP202406 六级] 计算得分(未成功)
    博客食用更佳:Myblog题目传送门分析:这道题是一个标准的dp。我们可以先预处理多个\(\texttt{abc}\)连成的字符串的最大值,之后可以按最长平台的方法处理。步骤:初值:这题不需要赋值,因为题目保证得分是正的,故初值为\(0\)。状态:\(dp_i\)表示连续\(i\)个\(\texttt{abc......
  • Redis缓存面试问题解析:如何有效管理缓存失效策略?
    在技术面试中,Redis缓存是一个常见的话题。面试官往往会考察候选人对缓存机制的理解以及在实际场景中的应用能力。本文将探讨一个在Redis缓存面试中经常被问到的问题,并深入解析其背后的概念和解决方案。面试问题:如何管理Redis缓存的失效策略?问题描述:在高并发的web应用中,缓存是提......
  • 题解:P10043 [CCPC 2023 北京市赛] 广播
    博客使用更佳:Myblog题目传送门这道题是一个标准的dp了,只不过它要倒序来做。还是分三步。初值:初值想必都知道吧,若要求最小值,就把初值设成无穷大,\(dp_{0,i}\)和\(dp_{i,0}\)都要设成\(i\),\(dp_{0,0}\)一定要赋值成\(0\),这是本人亲自犯过的错误QwQ。状态:\(dp_{i,j}......
  • AtCoder Beginner Contest 360 题解(C-E)
    C-MoveIt题目链接:C-MoveIt题目大意:有\(N\)个盒子和\(N\)个物品编号为\(1-N\),物品\(i\)在盒子\(A_i\)中,重量为\(W_i\),你可以进行一种操作将盒子中的一件物品移动到其他任意盒子中,代价为\(W_i\),求使得所有盒子中只存在一件物品的最小操作代价。题解:贪心,可以发现......
  • CF1843F2 题解
    题面注意到边权只有\(1,-1\),所以有结论:存在值为\(v\)的子段当且仅当\(v\in[\)最小子段和,最大子段和\(]\)。证明:因为移动区间端点,区间和变化连续(+1/-1),从最小子段移动到最大子段,子段和一定经过\(v\),所以得证。于是只要树剖维护最小最大子段和即可。和线段树上维护的数据......
  • CF440D 题解
    题面注意到划分完这棵树以后,每条连通块之间的边的一端一定相同,且是大小为\(k\)的连通块。于是考虑这个连通块的最高点,设\(f(i,j)\)为\(i\)点所在连通块大小为\(j\)时所需的最小边数。令\(f'(i)\)为原来的\(f(i)\)。对于\(i\)的每个\(s\inson(i)\),枚举从\(s\)......
  • CF56E 题解
    题面设骨牌\(i\)倒下之后会连带压倒\([i+1,r_i]\)的骨牌,那么有\(z_i=\max_{j=i+1}^{r_i}z_j+(j-i)\)考虑线段树优化dp,但是\((j-i)\)不好维护,所以套路地修改式子,得到:\(z_i+i=\max_{j=i+1}^{r_i}(z_j+j)\)所以线段树维护\(z_i+i\)的区间最大值即可,\(r_i\)可以二分求......
  • CF86D 题解
    题面看起来线段树之类的不好维护,但是移动区间的增量很好求,数据范围也能过,那么直接莫队就行了。设加入或删除了值\(x\),设原来区间内有\(cnt_x\)个,现在有\(cnt'_x\)个,那么增量就是\(x((cnt'_x)^2-(cnt_x)^2)\),直接求就好了。复杂度\(O(t\sqrtn)\)。#include<bits/stdc+......
  • CF567E 题解
    题面考虑如何一条边是必经之路:设\(cntl_i\)为从\(s\)到\(i\)走最短路的方案数,\(cntr_i\)为从\(i\)到\(t\)最短路方案数。由乘法原理,如果对于边\(e_i=(u,v)\),\(cnt_t=cnt_u\timescntr_v\),则\(e_i\)是最短路上的必经边,输出Yes即可。如果\(cnt_u\timescntr_v=0......