洛谷题目链接:[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. OpenCV学习4-----K-Nearest Neighbors(KNN)demo

    最近用到KNN方法,学习一下OpenCV给出的demo. demo大意是随机生成两团二维空间中的点,然后在500*500的二维空间平面上,计算每一个点属于哪一个类,然后用红色和绿色显示出来每一个点 如 ...

  2. Unicode,UTF-32,UTF-16,UTF-8到底是啥关系?

    编码的目的,就是给抽象的字符赋予一个数值,好在计算机里面表示.常见的ASCII使用8bit给字符编码,但是实际只使用了7bit,最高位没有使用,因此,只能表示128个字符:ISO-8859-1(也叫L ...

  3. 20145214实验一 Java开发环境的熟悉

    20145214实验一 Java开发环境的熟悉 使用JDK编译.运行简单的java程序 命令行下程序开发 在命令行下建立20145214实验目录,进入该目录后创建exp1目录. 把代码保存到exp1目 ...

  4. 百度安卓sdk开发

    一 key问题 1 在百度地图api控制台申请key的流程主要用到了app包,开发工具的开发sha1和发布sha1值,这2个值的获取就非常关键了. 一般来说我们都是在windows上开发安卓,使用an ...

  5. 解决爬虫浏览器中General显示 Status Code:304 NOT MODIFIED,而在requests请求时出现403被拦截的情况。

    在此,非常感谢 “完美风暴4” 的无私共享经验的精神    在Python爬虫爬取网站时,莫名遇到 浏览器中General显示  Status Code: 304 NOT MODIFIED 而在req ...

  6. 【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改区间查询

    题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i ...

  7. BZOJ4310 跳蚤(后缀数组+二分答案)

    注意到答案一定是原串的子串,于是考虑造出SA,二分答案是第几小的子串.第k小子串很容易在SA上求出.之后计算使他成为最大子串至少要在几个位置切割,对每个字典序比答案大的后缀,找到所有合法切割位置(求l ...

  8. Kingdom and its Cities - CF613D

    Meanwhile, the kingdom of K is getting ready for the marriage of the King's daughter. However, in or ...

  9. 进程间通讯-2(pipe)

    通过pipe 管道的方式也可以实现进程间通信. 父进程和子进程之间可以实现相互通信. from multiprocessing import Process, Pipe def f(conn): co ...

  10. [BZOJ3380] [USACO2004 Open]Cave Cows 1 洞穴里的牛之一

    Description ​ 很少人知道其实奶牛非常喜欢到洞穴里面去探险. ​ 洞窟里有N(1≤N≤100)个洞室,由M(1≤M≤1000)条双向通道连接着它们.每对洞室间 至多只有一条双向通道.有K( ...