BZOJ_3124_[Sdoi2013]直径_树形DP
BZOJ_3124_[Sdoi2013]直径_树形DP
Description
小Q最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有N-1 条边。 路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)
表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。
直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。
现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。
Input
第一行包含一个整数N,表示节点数。
接下来N-1行,每行三个整数a, b, c ,表示点 a和点b之间有一条长度为c
的无向边。
Output
共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有
直径经过的边的数量。
Sample Input
3 1 1000
1 4 10
4 2 100
4 5 50
4 6 100
Sample Output
2
【样例说明】
直径共有两条,3 到2的路径和3到6的路径。这两条直径都经过边(3, 1)和边(1, 4)。
HINT
对于100%的测试数据:2≤N≤200000,所有点的编号都在1..N的范围内,
边的权值≤10^9。
边权非负,可以用一个基于贪心的方法求直径。
以1为根进行dfs,求出每个点到根的距离dis1,令rt1为最大的一个点。
以rt1为根就能拽出来一条直径rt1---rt2,求出每个点到根的距离dis2。
所求的那些边一定是连续的,如果不连续则中间的那个一定可以替代边上的边。
考虑dis2[i]=dis2[rt2]的那些点i,一定可以和rt1形成又一条直径,于是可以把i和rt2的lca一下的那些边抠掉。
然后反过来再做一遍就可以啦。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 200050
typedef long long ll;
int head[N],to[N<<1],nxt[N<<1],val[N<<1],cnt,n,fa[N],dep[N],f[25][N],dis3[N];
ll dis1[N],dis2[N];
int rt1,rt2;
inline void add(int u,int v,int w) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void dfs1(int x,int y) {
int i;
if(dis1[x]>dis1[rt1]) rt1=x;
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y) {
dis1[to[i]]=dis1[x]+val[i];
dfs1(to[i],x);
}
}
}
void dfs2(int x,int y) {
int i; fa[x]=y; f[0][x]=y;
if(dis2[x]>dis2[rt2]) rt2=x;
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y) {
dep[to[i]]=dep[x]+1;
dis2[to[i]]=dis2[x]+val[i];
dfs2(to[i],x);
}
}
}
int lca(int x,int y) {
if(dep[x]<dep[y]) swap(x,y);
int i;
for(i=20;i>=0;i--) {
if(f[i][x]&&dep[f[i][x]]>=dep[y]) x=f[i][x];
}
if(x==y) return x;
for(i=20;i>=0;i--) {
if(f[i][x]&&f[i][y]&&f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
}
return f[0][x];
}
void dfs3(int x,int y) {
int i; f[0][x]=y;
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y) {
dep[to[i]]=dep[x]+1;
dis3[to[i]]=dis3[x]+val[i];
dfs3(to[i],x);
}
}
}
int main() {
scanf("%d",&n);
int i,x,y,z;
for(i=1;i<n;i++) {
scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z);
}
dfs1(1,0); dfs2(rt1,0);
int j;
for(i=1;(1<<i)<=n;i++) {
for(j=1;j<=n;j++) f[i][j]=f[i-1][f[i-1][j]];
}
int U=rt2;
for(i=1;i<=n;i++) if(dis2[i]==dis2[rt2]) U=lca(U,i);
memset(f,0,sizeof(f));
dfs3(rt2,0);
for(i=1;(1<<i)<=n;i++) {
for(j=1;j<=n;j++) f[i][j]=f[i-1][f[i-1][j]];
}
int D=rt1;
// printf("%d %d\n",rt1,rt2);
for(i=1;i<=n;i++) if(dis3[i]==dis3[rt1]) D=lca(D,i);
printf("%lld\n%d\n",dis2[rt2],dep[D]-dep[U]);
}
BZOJ_3124_[Sdoi2013]直径_树形DP的更多相关文章
- 2018.11.05 bzoj3124: [Sdoi2013]直径(树形dp)
传送门 一道sbsbsb树形dpdpdp 第一问直接求树的直径. 考虑第二问问的边肯定在同一条直径上均是连续的. 因此我们将直径记下来. 然后对于直径上的每一个点,dpdpdp出以这个点为根的子树中不 ...
- BZOJ_1864_[Zjoi2006]三色二叉树_树形DP
BZOJ_1864_[Zjoi2006]三色二叉树_树形DP 题意: 分析:递归建树,然后DP,从子节点转移. 注意到红色和蓝色没有区别,因为我们可以将红蓝互换而方案是相同的.这样的话我们只需要知道当 ...
- BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash
BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash 题意: 给你一棵树每个点有一个权值,要求修改最少的权值,使得每个节点的权值等于其儿子的权值和且儿子的权值都相等. 分析: 首先我们 ...
- B20J_4027_[HEOI2015]兔子与樱花_树形DP
B20J_4027_[HEOI2015]兔子与樱花_树形DP 题意: 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编 ...
- BZOJ_1040_[ZJOI2008]骑士_树形DP
BZOJ_1040_[ZJOI2008]骑士_树形DP 题意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各 界的赞扬.最近发生了一件可怕的事情,邪 ...
- BZOJ_1060_时态同步_树形DP
BZOJ_1060_时态同步_树形DP 题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1060 分析:水水的树形DP. 用儿子的最大值更新父亲, ...
- BZOJ_1827_[Usaco2010 Mar]gather 奶牛大集会_树形DP
BZOJ_1827_[Usaco2010 Mar]gather 奶牛大集会_树形DP 题意:Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来 ...
- BZOJ_4726_[POI2017]Sabota?_树形DP
BZOJ_4726_[POI2017]Sabota?_树形DP Description 某个公司有n个人, 上下级关系构成了一个有根树.其中有个人是叛徒(这个人不知道是谁).对于一个人, 如果他 下属 ...
- BZOJ_1304_[CQOI2009]叶子的染色_树形DP
BZOJ_1304_[CQOI2009]叶子的染色_树形DP Description 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白 ...
随机推荐
- Java编码辅助工具:Lombok —— 避免重复臃肿的代码,提高效率
在项目开发过程中,经常会涉及到一些调整很少但又必不可少的环节,比如实体类的Getter/Setter方法,ToString方法等.这时可以使用Lombok来避免这种重复的操作,减少非核心代码的臃肿,提 ...
- caffe-ubuntu1604-gtx850m-i7-4710hq----VGG_ILSVRC_16_layers.caffemodel
c++调用vgg16: ./build/install/bin/classification \ /media/whale/wsWin10/wsCaffe/model-zoo/VGG16//deplo ...
- Multicast注册中心
1 2 3 4 提供方启动时广播自己的地址. 消费方启动时广播订阅请求. 提供方收到订阅请求时,单播自己的地址给订阅者,如果设置了unicast=false,则广播给订阅者. 消费方收到提供方地址时, ...
- Erlang的系统限制
Erlang本身对进程数,原子长度等没有限制,但为了提高性能和节省内存,总会在实际实现中和运行环境中作出一些限制. 1.进程数量 缺省情况下同时存在的最大Erlang进程数量不超过2^18=26214 ...
- 关于 Delphi 中流的使用(7) 压缩与解压缩(TCompressionStream、TDecompressionStream)
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, For ...
- sqlite与sqlserver区别
1.查询时把两个字段拼接在一起 --sqlserver-- select Filed1+'@'+Filed2 from table --sqlite-- select Filed1||'@'||Fil ...
- 流畅的python学习笔记:第九章:符合python风格的对象
首先来看下对象的表现形式: class People(): def __init__(self,name,age): self.name=name self.a ...
- Android进程的生命周期
Android系统想要永久的保留一个应用进程差点儿是不可能的.所以系统就须要不断的释放老的或者不太重要的进程以便腾出足够的内存空间来执行新的或者更重要的进程,那么系统怎样决定哪个进程应该保留哪个应该杀 ...
- org.apache.catalina.Lifecycle
org.apache.catalina.Lifecycle start() * ----------------------------- * | ...
- (C)程序控制块(TCB)
程序控制块 1. 程序控制块 从代码上看,程序控制块就是一个结构体.例如: typedef struct tcb{ char * tast_name; //任务名字 int p; //任务重要级别 i ...