挺进
来源:互联网 发布:ubuntu安装deb软件命令 编辑:程序博客网 时间:2024/04/30 11:34
题目大意
给出一颗边权树,问你删除一条边然后将两部分直径相加的最大值为多少。
DP
我们知道求直径的dp方法:
f1[x]表示x往下走的最长链,f2[x]表示x往下走不与f1路径相交的最长链。
一颗树的直径长度=
其中f1[i]+f2[i]表示在i的子树中,经过i的最长路径。
现在我们对于本题,一个子树内的直径,可以额外保留一个num表示子树内最长直径(不包括经过本身的路径)
那么x子树内的直径=max(f1[x]+f2[x],num[x])
我们要如何知道删除子树x剩余部分的直径?
首先,处理f3[x]表示x往下走不与f1、f2路径相交的最长链,还要处理g表示f1、f2、f3分别是往哪一个儿子里走的。
同时,要处理num[x][0/1]表示x子树中(不包含x)f1[y]+f2[y]的最大的值和次大值,同时用who[x][0/1]表示最大和次大师哪一个儿子子树中的。
设f[x]表示考虑x的父亲的子树,删除x子树后的直径。
设x父亲为y,先考虑经过y的最长路径,于是讨论一下:如果y最长链要走到x,即为f2[y]+f3[y],如果y次长链要走到x,即为f1[y]+f3[y],否则为f1[y]+f2[y]。
然后考虑y子树内的(不包括y),如果f1[z]+f2[z]的最大值在x子树内,即为num[y][1]否则为num[y][0]。
于是可以处理出f[x]。
接着处理g[x]表示从x出发,不能往x的子树中走,走出的最长路径长度。
那么一定要走到父亲y,一定有x到y的边权。
然后,在y可以往下走,但不能往x里走,类似上面的情况讨论一下找出y往下走不能往x里走的最长链,记为mx。也可以往上走,就是g[y]。
还要处理一个gg[x],表示删除子树x后剩余部分的直径,显然剩余部分直径要么是f[x],要么是mx+g[y]。
求出gg后就可以统计答案了。
#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=100000+10;ll f1[maxn],f2[maxn],f3[maxn],num[maxn][2],who[maxn][2],f[maxn],g[maxn],gg[maxn],ans;int g1[maxn],g2[maxn],g3[maxn],cnt[maxn];int h[maxn],go[maxn*2],dis[maxn*2],next[maxn*2];int i,j,k,l,t,n,m,tot;int read(){ int x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x;}void add(int x,int y,int z){ go[++tot]=y; dis[tot]=z; next[tot]=h[x]; h[x]=tot;}void dfs(int x,int y,int z){ cnt[x]=z; ll mx,sum; int t=h[x]; while (t){ if (go[t]!=y){ dfs(go[t],x,dis[t]); if (f1[go[t]]+(ll)dis[t]>=f1[x]){ f3[x]=f2[x]; g3[x]=g2[x]; f2[x]=f1[x]; g2[x]=g1[x]; f1[x]=f1[go[t]]+(ll)dis[t]; g1[x]=go[t]; } else if (f1[go[t]]+(ll)dis[t]>=f2[x]){ f3[x]=f2[x]; g3[x]=g2[x]; f2[x]=f1[go[t]]+(ll)dis[t]; g2[x]=go[t]; } else if (f1[go[t]]+(ll)dis[t]>=f3[x]){ f3[x]=f1[go[t]]+(ll)dis[t]; g3[x]=go[t]; } mx=max(num[go[t]][0],f1[go[t]]+f2[go[t]]); if (mx>=num[x][0]){ num[x][1]=num[x][0]; who[x][1]=who[x][0]; num[x][0]=mx; who[x][0]=go[t]; } else if (mx>=num[x][1]){ num[x][1]=mx; who[x][1]=go[t]; } } t=next[t]; }}void dg(int x,int y,int z){ ll mx,sum; if (x!=1){ if (g1[y]==x) mx=f2[y]+f3[y]; else if (g2[y]==x) mx=f1[y]+f3[y]; else mx=f1[y]+f2[y]; if (who[y][0]==x) sum=num[y][1];else sum=num[y][0]; f[x]=max(mx,sum); if (g1[y]==x) mx=f2[y];else mx=f1[y]; g[x]=(ll)z+max(mx,g[y]); gg[x]=f[x]; gg[x]=max(gg[x],mx+g[y]); } int t=h[x]; while (t){ if (go[t]!=y) dg(go[t],x,dis[t]); t=next[t]; } mx=max(num[x][0],f1[x]+f2[x]); mx+=gg[x]; ans=max(ans,mx);}int main(){ freopen("data.in","r",stdin); n=read(); fo(i,1,n-1){ j=read();k=read();l=read(); add(j,k,l);add(k,j,l); } dfs(1,0,0); dg(1,0,0); printf("%lld\n",ans);}
- 挺进
- 挺进大别山
- JZOJ4727. 挺进
- Jzoj4727 挺进
- Borland挺进南极
- 巴萨挺进罗马!!!!
- UltraEdit挺进linux世界
- 挺进到firefox3.5
- 【JZOJ4727】挺进 题解
- IBM携手SAP挺进保险业
- 庆祝阿根廷挺进八强
- 中国共享软件:向海外挺进
- 再次向逆向工程挺进
- 【挖坑记】JZOJ 4727 挺进
- 小组成员终于可以大力挺进了。
- 庆祝tiobe排名ruby挺进前十!
- 名牌时报:用友挺进3G产业
- Scala挺进TIOBE前50了
- 使用Filter为请求方法添加跨域支持
- 【Android】JavaCV and OpenCV
- 引用类型String
- java
- 性能测试工具---Traceview
- 挺进
- 使用RecyclerView notifyItemChanged()出现图片闪烁问题解决
- java性能优化笔记(三)java程序优化
- 查询当前网段的所有在用IP
- xUtils===xUtils3.0基本使用规则
- 500B New Year Permutation(Floyd)
- php冒泡排序
- Git入门级使用教程
- 求2个字符串的最长公共子串长度