【JZOJ3213】【SDOI2013】直径
╰( ̄▽ ̄)╭
小 Q最近学习了一些图论知识。根据课本,有如下定义。
树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有 N-1 条边。
路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)表示点 a 和点 b 的路径上各边长度之和。称 dis(a,b)为 a、b 两个节点间的距离。
直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。
现在小 Q 想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。
对于 20%的测试数据:N≤100
对于 40%的测试数据:N≤1000
对于 70%的测试数据:N≤100000
对于 100%的测试数据:2≤N≤200000,所有点的编号都在 1..N 的范围内,边的权值≤10^9。
(⊙ ▽ ⊙)
首先必须知道的性质是:
对于任意两条直径,它们一定会有重叠部分。
反证法:
如果两条直径没有重叠部分,那么一定可以构造出一条更长的直径。
然后,在这条性质的基础上,我们扩展得到:
所有直径都有共同的重叠部分,而且满足题目要求的边就是这重叠部分。
证明:
设a,b,c分别是树的三条直径,且a∩b=α,a∩c=β。
令α∩β=∅,那么树就会出现环。
现在题目求的东西就变得很简单了。
利用树形动态规划,可以求出f[i],h[i],其中:
f[i]在i的子树中,从i向下走的最长链,并用F[i]记录它的方案数。
h[i]不在i的子树中,从i向上走的最长链,并用H[i]记录它的方案数。
显然当一个点i的f[i]+h[i]为所有点中的f+h的最大值时,它的父边被F[i]∗H[i]条直径经过。
答案就等于所有被最多直径经过的边的数目。
除此之外,还要特殊判断菊花图的情况。
时间复杂度为O(n)。
( ̄~ ̄)
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<math.h>
#define ll long long
using namespace std;
const char* fin="jzoj3213.in";
const char* fout="jzoj3213.out";
const ll inf=0x7fffffff;
const ll maxn=200007,maxm=maxn*2;
ll n,i,j,k,l,ans=0;
ll fi[maxn],ne[maxm],la[maxm],va[maxm],tot,fa[maxn],Fa[maxn];
ll f[maxn],F[maxn],g[maxn],G[maxn],h[maxn],H[maxn],dmt,num;
ll son[maxn],pre[maxn],Pre[maxn],suf[maxn],Suf[maxn],pp[maxn];
void add_line(ll a,ll b,ll c){
tot++;
ne[tot]=fi[a];
la[tot]=b;
va[tot]=c;
fi[a]=tot;
}
void dfs(ll v,ll from){
ll i,j,k;
fa[v]=from;
for (k=fi[v];k;k=ne[k])
if (la[k]!=from){
dfs(la[k],v);
if (f[la[k]]+va[k]==f[v]) F[v]+=F[la[k]];
else if (f[la[k]]+va[k]>f[v]){
F[v]=F[la[k]];
f[v]=f[la[k]]+va[k];
}
}
if (!F[v]) F[v]=1;
}
void geth(ll v,ll from){
ll i,j,k;
son[0]=0;
for (k=fi[v];k;k=ne[k]) if (la[k]!=from) son[++son[0]]=la[k],pp[son[0]]=va[k];
if (son[0]==1 && v==1) H[v]=1;
pre[0]=Pre[0]=0;
for (i=1;i<=son[0];i++){
if (f[son[i]]+pp[i]>pre[i-1]){
pre[i]=f[son[i]]+pp[i];
Pre[i]=F[son[i]];
}else if (f[son[i]]+pp[i]==pre[i-1]) pre[i]=pre[i-1],Pre[i]=Pre[i-1]+F[son[i]];
else pre[i]=pre[i-1],Pre[i]=Pre[i-1];
}
suf[son[0]+1]=Suf[son[0]+1]=0;
for (i=son[0];i>0;i--){
if (f[son[i]]+pp[i]>suf[i+1]){
suf[i]=f[son[i]]+pp[i];
Suf[i]=F[son[i]];
}else if (f[son[i]]+pp[i]==suf[i+1]) suf[i]=suf[i+1],Suf[i]=Suf[i+1]+F[son[i]];
else suf[i]=suf[i+1],Suf[i]=Suf[i+1];
}
for (i=1;i<=son[0];i++){
ll tmp,tmd;
if (pre[i-1]>suf[i+1]) tmp=pre[i-1],tmd=Pre[i-1];
else if (pre[i-1]<suf[i+1]) tmp=suf[i+1],tmd=Suf[i+1];
else tmp=suf[i+1],tmd=Pre[i-1]+Suf[i+1];
tmp+=pp[i];
if (tmp>h[v]+pp[i]) h[son[i]]=tmp,H[son[i]]=tmd;
else if (tmp<h[v]+pp[i]) h[son[i]]=h[v]+pp[i],H[son[i]]=H[v];
else h[son[i]]=h[v]+pp[i],H[son[i]]=H[v]+tmd;
}
for (k=fi[v];k;k=ne[k]) if (la[k]!=from) geth(la[k],v);
}
int main(){
scanf("%lld",&n);
for (i=1;i<n;i++){
scanf("%lld%lld%lld",&j,&k,&l);
add_line(j,k,l);
add_line(k,j,l);
}
dfs(1,0);
geth(1,0);
for (i=2;i<=n;i++){
if (dmt<h[i]+f[i]){
dmt=max(dmt,h[i]+f[i]);
num=H[i]*F[i];
}else if (dmt==h[i]+f[i]) num=max(num,H[i]*F[i]);
}
for (i=2;i<=n;i++)
if (dmt==h[i]+f[i]){
if (num==H[i]*F[i]) ans++;
if (h[i]==f[i] && F[i]*H[i]>1){
ans=0;
break;
}
}
printf("%lld\n%lld",dmt,ans);
return 0;
}
(⊙v⊙)
一条长度最长的链就是直径。
对于任意两条直径,它们一定会有重叠部分。
所有直径都有共同的重叠部分。
【JZOJ3213】【SDOI2013】直径的更多相关文章
- 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距离最长链左端点的距离 第二问 ...
- [洛谷P3304] [SDOI2013]直径
洛谷题目链接:[SDOI2013]直径 题目描述 小Q最近学习了一些图论知识.根据课本,有如下定义.树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度.如果一棵树有N个节点,可以证明其有且仅 ...
- 3124: [Sdoi2013]直径
3124: [Sdoi2013]直径 https://www.lydsy.com/JudgeOnline/problem.php?id=3124 分析: 所有直径都经过的边,一定都是连续的一段.(画个 ...
- 【BZOJ3124】[Sdoi2013]直径 树形DP(不用结论)
[BZOJ3124][Sdoi2013]直径 Description 小Q最近学习了一些图论知识.根据课本,有如下定义.树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度.如果一棵树有N个节 ...
- BZOJ_3124_[Sdoi2013]直径_树形DP
BZOJ_3124_[Sdoi2013]直径_树形DP Description 小Q最近学习了一些图论知识.根据课本,有如下定义.树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度.如果一棵 ...
- Bzoj 3124: [Sdoi2013]直径 题解
3124: [Sdoi2013]直径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1222 Solved: 580[Submit][Status] ...
- 【bzoj3124】 Sdoi2013—直径
http://www.lydsy.com/JudgeOnline/problem.php?id=3124 (题目链接) 题意 求树的直径以及直径的交. Solution 我的想法超麻烦,经供参考..思 ...
- bzoj 3124: [Sdoi2013]直径
#include<cstdio> #include<iostream> #define M 400009 #define ll long long using namespac ...
- bzoj 3124 [Sdoi2013]直径(dfs)
Description 小Q最近学习了一些图论知识.根据课本,有如下定义.树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度.如果一棵树有N个节点,可以证明其有且仅有N-1 条边. 路径:一 ...
随机推荐
- leyou_03_cors解决ajax的跨域请求问题
1.为什么会有跨域问题 因为跨域问题是浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是与当前页域名相同的路径,这能有效的阻止跨站攻击. 因此:跨域问题 是针对ajax的一种限制 ...
- jeecms框架单点登录功能的实现
单点登录的功能实现主要原理: 1: 在点击登录按钮的时候使用reponse.addCookie()方法向浏览器发送cookie: 2: 在前段拦截器中的request.getCookie()在接收到设 ...
- 如何使用JMeter 进行压力测试
文件转载至:https://jingyan.baidu.com/album/a681b0de5b85db3b184346b9.html?picindex=2 1.打开JMeter, 更改语言为中文,官 ...
- debian下编译安装poco
系统环境: debian版本:Linux localhost.localdomain 3.10.0-862.14.4.el7.x86_64 #1 SMP Wed Sep 26 15:12:11 UTC ...
- Redis 分布式锁进化史
按:系统架构经过多年演进,现在越来越多的系统采用微服务架构,而说到微服务架构必然牵涉到分布式,以前单体应用加锁是很简单的,但现在分布式系统下加锁就比较难了,我之前曾简单写过一篇文章,关于分布式锁的实现 ...
- MySQL用户权限详细汇总
1,MySQL权限体系 mysql 的权限体系大致分为5个层级:全局层级:全局权限适用于一个给定服务器中的所有数据库.这些权限存储在mysql.user表中.GRANT ALL ON .和REVOKE ...
- 粗浅看 Tomcat系统架构分析
原文出处: 吴士龙 http://www.importnew.com/21112.html Tomcat的结构很复杂,但是Tomcat也非常的模块化,找到了Tomcat最核心的模块,就抓住了Tomca ...
- CF 529B Group Photo 2 (online mirror version)
传送门 解题思路 这道题要用到贪心的思路,首先要枚举一个h的最大值,之后check.如果这个东西的w[i]与h[i]都大于枚举的值就直接return false,如果w[i]比这个值小,h[i]比这个 ...
- jeecms使用小结
前言: 使用jeecmsV9已经有一段时间,现在PC端的二次开发基本进入尾声,手机端的开发即将开始 ,由于项目时间比较紧,开发时不是每个人都会使用它自带的标签,所以在PC端开发的时候浪费了大量时间,为 ...
- mysql limit的使用方法
mysql的分页limit的使用方法大全 .取表中的n行之后的m条元组(limit n,m) ,; //取出student表中第4行后的8条元组(这里的区间是左开右闭) .取出表中前m行元素(limi ...