【JZOJ3213】【SDOI2013】直径
来源:互联网 发布:python 写文件 中文 编辑:程序博客网 时间:2024/05/18 04:57
╰( ̄▽ ̄)╭
小 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。
(⊙ ▽ ⊙)
首先必须知道的性质是:
对于任意两条直径,它们一定会有重叠部分。
反证法:
如果两条直径没有重叠部分,那么一定可以构造出一条更长的直径。
然后,在这条性质的基础上,我们扩展得到:
所有直径都有共同的重叠部分,而且满足题目要求的边就是这重叠部分。
证明:
设
令
现在题目求的东西就变得很简单了。
利用树形动态规划,可以求出
显然当一个点
答案就等于所有被最多直径经过的边的数目。
除此之外,还要特殊判断菊花图的情况。
时间复杂度为
( ̄~ ̄)
#include<iostream>#include<algorithm>#include<stdio.h>#include<string.h>#include<math.h>#define ll long longusing 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】直径
- 【SDOI2013】直径
- [Sdoi2013]直径
- 【sdoi2013】直径
- 【bzoj3124】: [Sdoi2013]直径
- BZOJ3124: [Sdoi2013]直径
- bzoj3124 [Sdoi2013]直径 树的直径
- bzoj3124 [Sdoi2013]直径 直径+树形dp
- BZOJ 3124 [Sdoi2013]直径 DFS
- bzoj3124[Sdoi2013]直径(树dp)
- [BZOJ3124][SDOI2013]直径(DFS)
- BZOJ3124 [sdoi2013]直径(树上的dfs)
- [BZOJ3124][Sdoi2013]直径(树形dp)
- bzoj 3124: [Sdoi2013]直径 (dfs)
- [BZOJ3124][Sdoi2013]直径(树形dp)
- 3124: [Sdoi2013]直径【dfs】【树的直径】【外向树】
- BZOJ 3124: [Sdoi2013]直径 (随便写写就好了)
- [Sdoi2013]assassin
- java生成pdf 导出
- Python 字符串格式化
- iOS8左滑出现三个按钮
- 扩大View点击范围
- Node.js 究竟是什么?
- 【JZOJ3213】【SDOI2013】直径
- cadence16.6为例说明已经破解后安装HOTFIX的方法
- AndroidStudio 本地两个项目联调
- 透明通知栏透明导航栏
- Java开发中的23种设计模式详解
- Android Studio常用快捷键 格式化代码 Alt+Ctrl+L ,提取全局变量...
- 竞品分析全览
- 互联网系统架构的演进
- 【BZOJ 3438】小M的作物 最大权闭合子图