洛谷题目链接:[SDOI2013]直径

题目描述

小Q最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有N-1 条边。

路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。

直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。

现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。

输入输出格式

输入格式:

第一行包含一个整数N,表示节点数。 接下来N-1行,每行三个整数a, b, c ,表示点 a和点b之间有一条长度为c的无向边。

输出格式:

共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有直径经过的边的数量。

输入输出样例

输入样例#1:

6

3 1 1000

1 4 10

4 2 100

4 5 50

4 6 100

输出样例#1:

1110

2

说明

【样例说明】 直径共有两条,3 到2的路径和3到6的路径。这两条直径都经过边(3, 1)和边(1, 4)。

对于100%的测试数据:2<=N<=200000,所有点的编号都在1..N的范围内,边的权值<=10^9。


一句话题意: 给出一颗树,要求出树上所有直径相交的长度.


题解: 首先处理出树上的任意一条直径,然后处理出直径上的点到它的子树(不包含在直径上的点)中最深的距离.如果这个距离和它到直径一端的距离相同的话,就说明它的子树中含有直径中的一段.那么直径的这一段相同的长度都是不能算入最终全部直径相交的长度中的.

那么做法就可以得出了:确定一条直径,对直径上的每一个点判断它子树中是否存在有直径的一部分,如果有,那么就把指针向另一边移动,最后左右指针相减就是答案了.

最后答案要开long long

#include<bits/stdc++.h>
using namespace std;
const int N = 200000+5;
typedef int _int;
#define int long long int n, last[N], ecnt = 0;
int pre[N], dep[N], fa[N], f[N], len = 0, L, R, vis[N], node[N], cnt = 0, mx[N], dist[N], ansl, ansr; struct edge{
int to, nex, w;
}e[N*2]; void add(int x, int y, int z){
e[++ecnt].to = y, e[ecnt].w = z, e[ecnt].nex = last[x], last[x] = ecnt;
} void dfs(int x, int las, int deep){
dep[x] = deep, fa[x] = las;
for(int to, i=last[x];i;i=e[i].nex){
to = e[i].to; if(to == las) continue;
dfs(to, x, deep+1);
if(len < f[x]+f[to]+e[i].w) len = f[x]+f[to]+e[i].w, L = pre[x], R = pre[to];
if(f[x] < f[to]+e[i].w) f[x] = f[to]+e[i].w, pre[x] = pre[to];
}
} void get(int x, int lca){
if(x == lca){ node[++cnt] = x; return; }
get(fa[x], lca), node[++cnt] = x;
} int get_dis(int x, int f){
int res = 0;
for(int to, i=last[x];i;i=e[i].nex){
to = e[i].to; if(to == f || vis[to]) continue;
res = max(res, e[i].w+get_dis(to, x));
}
return res;
} void solve(){
int x = L, y = R, lca;
if(dep[x] < dep[y]) swap(x, y);
while(dep[x] > dep[y]) vis[x] = 1, x = fa[x];
if(x == y) vis[x] = 1, lca = x;
else {
while(x != y) vis[x] = vis[y] = 1, x = fa[x], y = fa[y];
vis[x] = 1, lca = x;
}
x = L, y = R;
while(x != lca) node[++cnt] = x, x = fa[x]; get(y, lca);
for(int i=1;i<=cnt;i++) mx[node[i]] = get_dis(node[i], -1);
for(int i=2;i<=cnt;i++)
for(int j=last[node[i]];j;j=e[j].nex)
if(e[j].to == node[i-1]) dist[node[i]] = dist[node[i-1]]+e[j].w;
ansl = 1, ansr = cnt;
for(int i=2;i <= cnt;i++)
if(dist[node[i]] == mx[node[i]]) ansl = i;
for(int i=cnt-1; i >= 1 && ansr >= ansl; i--)
if(dist[node[cnt]]-dist[node[i]] == mx[node[i]]) ansr = i;
} _int main(){
ios::sync_with_stdio(false);
int x, y, z; cin >> n;
for(int i=1;i<=n;i++) pre[i] = i;
for(int i=1;i<n;i++) cin >> x >> y >> z, add(x, y, z), add(y, x, z);
dfs(1, -1, 1), solve();
cout << len << endl << ansr-ansl << endl;
return 0;
}

[洛谷P3304] [SDOI2013]直径的更多相关文章

  1. Bzoj3197/洛谷3296 [SDOI2013]刺客信条assassin(树的重心+树Hash+树形DP+KM)

    题面 Bzoj 洛谷 题解 (除了代码均摘自喻队的博客,可是他退役了) 首先固定一棵树,枚举另一棵树,显然另一棵树只有与这棵树同构才有可能产生贡献 如果固定的树以重心为根,那么另一棵树最多就只有重心为 ...

  2. 【洛谷 P3304】[SDOI2013]直径(树的直径)

    题目链接 题意,求一棵树被所有直径经过的边的条数. 这题是我们8.25KS图论的最后一题,当时我果断打了暴力求所有直径然后树上差分统计的方法,好像有点小问题,boom0了. 考完改这题,改了好久,各种 ...

  3. 洛谷 P3299 [SDOI2013]保护出题人 解题报告

    P3299 [SDOI2013]保护出题人 题目描述 出题人铭铭认为给SDOI2012出题太可怕了,因为总要被骂,于是他又给SDOI2013出题了. 参加SDOI2012的小朋友们释放出大量的僵尸,企 ...

  4. 洛谷 P3297 [SDOI2013]逃考 解题报告

    P3297 [SDOI2013]逃考 题意 给一个平面矩形,里面有一些有标号点,有一个是人物点,人物点会被最近的其他点控制,人物点要走出矩形,求人物点最少被几个点控制过. 保证一开始只被一个点控制,没 ...

  5. luogu P3304 [SDOI2013]直径

    树的直径两遍dfs救星了 至于一定在直径中的边数,可以发现这些边一定是连续的(不然你两条直径中间能有空挡?),然后,如果某个点往下有多条直径,那么这条点以下都不算入答案.所以以直径分别两端点为根,找出 ...

  6. 洛谷 P3302 [SDOI2013]森林 解题报告

    P3302 [SDOI2013]森林 题目描述 小\(Z\)有一片森林,含有\(N\)个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有\(M\)条边. 小Z希望执行\(T\)个操作,操 ...

  7. 洛谷P3307 [SDOI2013]项链 [polya定理,莫比乌斯反演]

    传送门 思路 很明显的一个思路:先搞出有多少种珠子,再求有多少种项链. 珠子 考虑这个式子: \[ S3=\sum_{i=1}^a \sum_{j=1}^a\sum_{k=1}^a [\gcd(i,j ...

  8. [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)

    传送门 突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288 首先有两个操作,一个查询,一个连接 查询的话,直接 ...

  9. 洛谷 P3302 [SDOI2013]森林

    ->题目链接 题解: #include<queue> #include<cstdio> #include<cstring> #include<iostr ...

随机推荐

  1. Linux查看物理CPU个数,核数,逻辑CPU个数;内存信息

    # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数 # 查看物理CPU个数 cat /proc/cpuinfo| ...

  2. 直接管理内存——new和delete

    一.运算符new 1. 使用new动态分配对象 在自由空间分配的内存是无名的,故new无法为其分配的对象命名,而是返回一个指向该对象的指针 int *pi = new int; //pi指向一个动态分 ...

  3. 对编码内容多次UrlDecode

    对编码内容多次UrlDecode,并不会影响最终结果. 尝试阅读了微软的源代码,不过不容易读懂. 网址:https://referencesource.microsoft.com/#System/ne ...

  4. PokeCats开发者日志(十一)

      现在是PokeCats游戏开发的第六十天的上午,易版权的状态变为了待收证,但愿不久就能送到了吧.

  5. 基于gulp的前端自动化开发构建

    就前端的发展而言会越来越朝着后端的标准化靠近,后端的工程化以及模块化都很成熟.基于这样一个思路,开始探索如何优化目前的开发流程.而使用的工具就是gulp. 个人觉得gulp比较webpack更为简单实 ...

  6. 从1到n的阶乘的和(python)

    今天在百度上逛一些ctf的平台,偶然发现一道编程题,于是乎,便用我刚刚学的python知识解了这道题 题目的描述是这样的: 计算1!+2!+3!+...+6666!后五位. 这个计算量很大啊,我还是用 ...

  7. Python实现XML的操作

    本文从以下两个方面, 用Python实现XML的操作: 一. minidom写入XML示例1 二. minidom写入XML示例2 三. ElementTree写入/修改示例 四. ElementTr ...

  8. windows默认TEMP环境

    留着是为了等出问题的时候能找着改回来 Administrator 的用户变量 TEMP     %USERPROFILE%\AppData\Local\Temp TMP        %USERPRO ...

  9. C# 知识回顾 - 扩展方法解析

    在使用面向对象的语言进行项目开发的过程中,较多的会使用到“继承”的特性,但是并非所有的场景都适合使用“继承”特性,在设计模式的一些基本原则中也有较多的提到. 继承的有关特性的使用所带来的问题:对象的继 ...

  10. WPF值转换实例

    WPF绑定功能非常方便,有时候点击某值时在另t一处显示此值的另一表现形式或调用其对应的其它值,用WPF值转换功能会很方便,下面就一LISTBOX和TEXTBLOCK控件,把LISTBOX中的值转换成除 ...