BZOJ3124 [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
的无向边。
输出格式
共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有
直径经过的边的数量。
输入样例
6
3 1 1000
1 4 10
4 2 100
4 5 50
4 6 100
输出样例
1110
2
提示
【样例说明】
直径共有两条,3 到2的路径和3到6的路径。这两条直径都经过边(3, 1)和边(1, 4)。
对于100%的测试数据:2≤N≤200000,所有点的编号都在1..N的范围内,
边的权值≤10^9。
题解
首先我们先求出树的直径,解决问题1
然后对于这条我们任意找出的直径,答案一定在这条直径上,因为其它直径对于这条直径来说,没有被访问到
我们就看看这条直径上还有那些直径经过
我们求出直径上每个点的外向树到这条直径的最远距离
如果存在一个点的最远距离 + 次远距离 = 直径长,那么答案是0
否则求出直径上每个点向左能延伸的最远距离及该距离下最近的拐点,向右也求出
记为ml,mr,拐点记为pre和post,直径长为L
如果\(ml + mr = L\),说明有一条直径经过区间\([pre,post]\),那么区间外的边一定不是答案
如此反复,我们得到若干个区间,排个序取公共部分就是答案
埋头乱码竟1A,,
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 200005,maxm = 400005,INF = 100000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int to,nxt,w;}ed[maxm];
inline void build(int u,int v,int w){
ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
}
int n,rt,fa[maxn],c[maxn],vis[maxn],tot;
LL d[maxn],sum[maxn],ansL;
void dfs1(int u){
if (d[u] > d[rt]) rt = u;
Redge(u) if ((to = ed[k].to) != fa[u]){
d[to] = d[u] + ed[k].w; fa[to] = u;
dfs1(to);
}
}
void solve1(){
dfs1(1);
d[rt] = 0; fa[rt] = 0;
dfs1(rt);
for (int i = rt; i; i = fa[i]){
c[++tot] = i;
sum[tot] = d[i];
vis[i] = true;
}
reverse(c + 1,c + 1 + tot);
reverse(sum + 1,sum + 1 + tot);
printf("%lld\n",ansL = d[rt]);
}
LL gmax,hmax,md[maxn],ml[maxn],mr[maxn];
int pre[maxn],post[maxn];
void dfs2(int u){
if (d[u] >= gmax){
hmax = gmax;
gmax = d[u];
}
else if (d[u] > hmax){
hmax = d[u];
}
vis[u] = true;
Redge(u) if (!vis[to = ed[k].to]){
d[to] = d[u] + ed[k].w;
dfs2(to);
}
}
struct inter{int l,r;}e[2 * maxn];
int cnt,tag[maxn];
inline bool operator <(const inter& a,const inter& b){
return a.l == b.l ? a.r < b.r : a.l < b.l;
}
void solve2(){
for (int i = 1; i <= tot; i++){
gmax = hmax = -INF; d[c[i]] = 0;
dfs2(c[i]);
md[i] = gmax;
if (gmax + hmax == ansL){
puts("0");
return;
}
}
ml[1] = md[1]; pre[1] = 1;
for (int i = 2; i <= tot; i++){
if (md[i] >= ml[i - 1] + sum[i] - sum[i - 1]){
pre[i] = i;
ml[i] = md[i];
}
else {
pre[i] = pre[i - 1];
ml[i] = ml[i - 1] + sum[i] - sum[i - 1];
}
}
mr[tot] = md[tot]; post[tot] = tot;
for (int i = tot - 1; i; i--){
if (md[i] >= mr[i + 1] + sum[i + 1] - sum[i]){
post[i] = i;
mr[i] = md[i];
}
else {
post[i] = post[i + 1];
mr[i] = mr[i + 1] + sum[i + 1] - sum[i];
}
}
for (int i = 1; i <= tot; i++){
if (pre[i] == post[i]) continue;
if (ml[i] + mr[i] == ansL){
e[++cnt] = (inter){1,pre[i]};
e[++cnt] = (inter){post[i],tot};
}
}
sort(e + 1,e + 1 + cnt);
int l = 0,r = -1;
for (int i = 1; i <= cnt; i++){
if (e[i].l > r + 1){
for (int j = l; j <= r; j++) tag[j] = true;
l = e[i].l;
r = e[i].r;
}
else r = max(r,e[i].r);
}
for (int j = l; j <= r; j++) tag[j] = true;
int ans = 0;
for (int i = 1; i <= tot; i++){
if (i != 1 && i != tot && !tag[i]){
ans++;
if (tag[i - 1]) ans++;
}
}
printf("%d\n",ans);
}
int main(){
n = read();
int a,b,w;
for (int i = 1; i < n; i++){
a = read(); b = read(); w = read();
build(a,b,w);
}
solve1();
solve2();
return 0;
}
BZOJ3124 [Sdoi2013]直径 【树的直径】的更多相关文章
- POJ 1985.Cow Marathon-树的直径-树的直径模板(BFS、DFS(vector存图)、DFS(前向星存图))
Cow Marathon Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 7536 Accepted: 3559 Case ...
- [SDOI2013]直径 (树的直径,贪心)
题目链接 Solution 我们直接找到一条直径 \(s\),起点为 \(begin\),终点为 \(end\). 从前往后遍历点 \(u\) ,若子树中最大的距离与 \(dis(u,begin)\) ...
- 树形DP 学习笔记(树形DP、树的直径、树的重心)
前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...
- bzoj3124: [Sdoi2013]直径 树形dp two points
题目链接 bzoj3124: [Sdoi2013]直径 题解 发现所有直径都经过的边 一定在一条直径上,并且是连续的 在一条直径上找这段区间的两个就好了 代码 #include<map> ...
- bzoj千题计划134:bzoj3124: [Sdoi2013]直径
http://www.lydsy.com/JudgeOnline/problem.php?id=3124 第一问: dfs1.dfs2 dfs2中记录dis[i]表示点i距离最长链左端点的距离 第二问 ...
- 2018.11.05 bzoj3124: [Sdoi2013]直径(树形dp)
传送门 一道sbsbsb树形dpdpdp 第一问直接求树的直径. 考虑第二问问的边肯定在同一条直径上均是连续的. 因此我们将直径记下来. 然后对于直径上的每一个点,dpdpdp出以这个点为根的子树中不 ...
- SDOI2013直径(树的直径)
题目描述: 点这里 题目大意: 就是在一个树上找其直径的长度是多少,以及有多少条边满足所有的直径都经过该边. 题解: 首先,第一问很好求,两边dfs就行了,第一次从任一点找距它最远的点,再从这个点找距 ...
- poj2631 求树的直径裸题
题目链接:http://poj.org/problem?id=2631 题意:给出一棵树的两边结点以及权重,就这条路上的最长路. 思路:求实求树的直径. 这里给出树的直径的证明: 主要是利用了反证法: ...
- poj1985 Cow Marathon (求树的直径)
Cow Marathon Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 3195 Accepted: 1596 Case ...
随机推荐
- Oracle汇总
1.数据库事务并发会产生那些问题?有哪些隔离级别,分别能够避免什么错误,而无法避免什么错误? a.事务并发会导致三种问题:脏读.不可重复读.幻象读 脏读:读取了未提交的数据 不可重复读:前后读取同一行 ...
- Flask信号流程
首先先我们来看看Flask里面的信号是什么样的,我们可以找到一个叫signals.py的文件 这里面是所有定义了的后面请求流程中会用到的信号 二.哪些地方用到了信号 1.请求app上下文时执行的,在执 ...
- ftpclient 遇到的一些问题
1. FTPFile[] files=ftpClient.listFiles(ftpDirectory); 没有数据 public static boolean ftpLogin(String ser ...
- windows 操作系统种类
@hcy 敬请访问:http://blog.sina.com.cn/iihcy Microsoft公司从1983年开始研制Windows系统,最初的研制目标是在MS-DOS的基础上提供一个多任务的图形 ...
- iOS 查看包架构信息
lipo -info libUMSocial_Sdk_4.2.a 查看包架构信息
- myna代码
https://github.com/TalkingData/Myna/tree/master/Dataset https://github.com/TalkingData/Myna
- linux_1
注: 创建软连接: "ln -s xxx 路径1" 在路径1创建xxx的软连接 特点: 1.文件类型 l 2.相当于windows的快捷方式 创建硬链接: "ln xxx ...
- 题解 P1189 SEARCH
(传送门)[https://www.luogu.org/problemnew/show/P1189] 先反省一波:我以后再也不用getchar()+scanf了(日常爆零) 算是比较裸的搜索吧,在下用 ...
- bootstrap历练实例: 垂直胶囊式的导航菜单
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- oracle count 百万级 分页查询记要总数、总条数优化
oracle count 百万级 分页查询记录总数.总条数优化 oracle count 百万级 查询记录总数.总条数优化 最近做一个项目时,做分页时,发现分页查询速度很慢,分页我做的是两次查询,一次 ...