#树形dp,直径#51nod 1812 树的双直径
题目
给定一棵树,边权是整数 \(c_i\) ,找出两条不相交的链(没有公共点),
使得链长的乘积最大(链长定义为这条链上所有边的权值之和,如果这条链只有1个点则链长视为0)。
\(n\leq 4*10^5,|c_i|\leq 10^9\)
分析
首先考虑一条直径就是维护最大值和次大值,
然后换根就可以得到经过任意一点的直径 \(f[x]\)。
但是两条直径还要考虑不相交,那么分类讨论一下。
如果直径处在两个不同的子树内,可以提前处理 \(dp[x]\) 表示 \(x\) 的子树内 \(f[x]\) 的最大值。
对于 \(x\),求出 \(\max\{dp[y]*dp[y']\}\) 即可
否则,直径一定可以被表示成一条经过 \(x\) 且不经过 \(y\),一条在以 \(y\) 为根的子树内,也就是 \(dp[y]\)
\(x\) 这部分挺难求的,任意一点直径却并没有保证它不经过 \(y\),所以还要维护第三大值,剔除掉 \(y\) 的贡献,再贡献给 \(y\)
最后如果要卡常,就只在答案这里开 __int128 就可以了。
心路历程:提交了16次,一开始根本没发现可以处在两个不同的子树内,而且对求第三大值犹豫再三。
而且调题真的很难受,没求处在两个不同的子树内的时候,只有一个点是RE的(玄学,令根为 \(\left\lceil\frac{n}{2}\right\rceil\) 就会少点RE)
但是其实调题的时候做法还不够完整,因为这么做,我第五个点是WA的,接着就一直查错,然后发现了这种情况,一开始想复杂了,后来利用 \(\max\{dp[y]*dp[y']\}\) 就可以了
代码
#include <cstdio>
#include <cctype>
using namespace std;
const int N=400011; typedef long long lll;
struct node{int y,w,next;}e[N<<1]; __int128 ans;
lll Mn[N],Mx[N],mn[N][3],mx[N][3]; int et=1,as[N],n;
int iut(){
int ans=0,f=1; char c=getchar();
while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans*f;
}
void print(__int128 ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void Max(lll &a,lll b){a=a>b?a:b;}
void Min(lll &a,lll b){a=a<b?a:b;}
__int128 max(__int128 a,__int128 b){return a>b?a:b;}
void dfs1(int x,int fa){
for (int i=as[x],flag;i;i=e[i].next)
if (e[i].y!=fa){
dfs1(e[i].y,x);
flag=1;
for (int k=0;k<3&&flag;++k)
for (int j=k;j<3&&flag;++j)
if (mn[x][j]>mn[e[i].y][k]+e[i].w){
for (int _j=2;_j>j;--_j) mn[x][_j]=mn[x][_j-1];
mn[x][j]=mn[e[i].y][k]+e[i].w,flag=0;
}
flag=1;
for (int k=0;k<3&&flag;++k)
for (int j=k;j<3&&flag;++j)
if (mx[x][j]<mx[e[i].y][k]+e[i].w){
for (int _j=2;_j>j;--_j) mx[x][_j]=mx[x][_j-1];
mx[x][j]=mx[e[i].y][k]+e[i].w,flag=0;
}
ans=max(ans,(__int128)Mn[x]*Mn[e[i].y]);
ans=max(ans,(__int128)Mx[x]*Mx[e[i].y]);
Min(Mn[x],Mn[e[i].y]),Max(Mx[x],Mx[e[i].y]);
}
Min(Mn[x],mn[x][0]+mn[x][1]);
Max(Mx[x],mx[x][0]+mx[x][1]);
}
void dfs2(int x,int fa){
lll MN[3],MX[3];
for (int i=0;i<3;++i) MN[i]=mn[x][i],MX[i]=mx[x][i];
for (int i=as[x],flag;i;i=e[i].next)
if (e[i].y!=fa){
for (int j=0;j<3;++j) mn[x][j]=MN[j],mx[x][j]=MX[j];
flag=1;
for (int k=0;k<3&&flag;++k)
for (int j=k;j<3&&flag;++j)
if (mn[x][j]==mn[e[i].y][k]+e[i].w){
for (int _j=j;_j<2;++_j) mn[x][_j]=mn[x][_j+1];
mn[x][2]=flag=0;
}
flag=1;
for (int k=0;k<3&&flag;++k)
for (int j=k;j<3&&flag;++j)
if (mx[x][j]==mx[e[i].y][k]+e[i].w){
for (int _j=j;_j<2;++_j) mx[x][_j]=mx[x][_j+1];
mx[x][2]=flag=0;
}
flag=1;
for (int k=0;k<3&&flag;++k)
for (int j=k;j<3&&flag;++j)
if (mn[e[i].y][j]>mn[x][k]+e[i].w){
for (int _j=2;_j>j;--_j) mn[e[i].y][_j]=mn[e[i].y][_j-1];
mn[e[i].y][j]=mn[x][k]+e[i].w,flag=0;
}
flag=1;
for (int k=0;k<3&&flag;++k)
for (int j=k;j<3&&flag;++j)
if (mx[e[i].y][j]<mx[x][k]+e[i].w){
for (int _j=2;_j>j;--_j) mx[e[i].y][_j]=mx[e[i].y][_j-1];
mx[e[i].y][j]=mx[x][k]+e[i].w,flag=0;
}
ans=max(ans,(__int128)Mn[e[i].y]*(mn[x][0]+mn[x][1]));
ans=max(ans,(__int128)Mx[e[i].y]*(mx[x][0]+mx[x][1]));
dfs2(e[i].y,x);
}
}
int main(){
n=iut();
for (int i=1;i<n;++i){
int x=iut(),y=iut(),w=iut();
e[++et]=(node){y,w,as[x]},as[x]=et;
e[++et]=(node){x,w,as[y]},as[y]=et;
}
dfs1((n+1)>>1,0),dfs2((n+1)>>1,0);
print(ans);
return 0;
}
#树形dp,直径#51nod 1812 树的双直径的更多相关文章
- 51nod 1812 树的双直径 题解【树形DP】【贪心】
老了-稍微麻烦一点的树形DP都想不到了. 题目描述 给定一棵树,边权是整数 \(c_i\) ,找出两条不相交的链(没有公共点),使得链长的乘积最大(链长定义为这条链上所有边的权值之和,如果这条链只有 ...
- 51nod1812树的双直径(换根树DP)
传送门:http://www.51nod.com/Challenge/Problem.html#!#problemId=1812 题解:头一次写换根树DP. 求两条不相交的直径乘积最大,所以可以这样考 ...
- LOJ2250 [ZJOI2017] 仙人掌【树形DP】【DFS树】
题目分析: 不难注意到仙人掌边可以删掉.在森林中考虑树形DP. 题目中说边不能重复,但我们可以在结束后没覆盖的边覆盖一个重复边,不改变方案数. 接着将所有的边接到当前点,然后每两个方案可以任意拼接.然 ...
- hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。
/** 题目:hdu6035 Colorful Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:给定一棵树,每个节点有一个颜色值.定 ...
- 51nod"省选"模测 A 树的双直径(树形dp)
题意 题目链接 Sol 比赛结束后才调出来..不多说啥了,就是因为自己菜. 裸的up-down dp,维护一下一个点上下的直径就行,一开始还想了个假的思路写了半天.. 转移都在代码注释里 毒瘤题目卡空 ...
- hdu 2196(方法1:经典树形DP+方法2:树的直径)
Computer Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- 【洛谷】2607: [ZJOI2008]骑士【树形DP】【基环树】
P2607 [ZJOI2008]骑士 题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一 ...
- HDU4612(Warm up)2013多校2-图的边双连通问题(Tarjan算法+树形DP)
/** 题目大意: 给你一个无向连通图,问加上一条边后得到的图的最少的割边数; 算法思想: 图的边双连通Tarjan算法+树形DP; 即通过Tarjan算法对边双连通缩图,构成一棵树,然后用树形DP求 ...
- 【BZOJ-2286】消耗战 虚树 + 树形DP
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2120 Solved: 752[Submit][Status] ...
- BZOJ5287 HNOI2018毒瘤(虚树+树形dp)
显然的做法是暴力枚举非树边所连接两点的选或不选,大力dp.考场上写的是最暴力的O(3n-mn),成功比大众分少10分.容斥或者注意到某些枚举是不必要的就能让底数变成2.但暴力的极限也就到此为止. 每次 ...
随机推荐
- Java Http客户端选型
JDK自带 HTTPURLConnect:功能单一 Apache HttpClient https://hc.apache.org/index.html 是一个比较古老的HTTP框架,使用非常普遍. ...
- Docker实践之06-访问仓库
目录 什么是仓库 一.Docker Hub 注册 登录 拉取镜像 推送镜像 自动创建 二.私有仓库 Docker Registry 安装Docker Registry 在私有仓库上传/搜索/下载镜像 ...
- 项目实战:Qt+OSG三维2D文字实时效果查看工具
需求 OSG三维中2D文字的基本属性较多,方便实时查看效果,并出对应文本代码. Demo 工具下载地址 CSDN免积分下载地址:https://download.csdn.net ...
- fastdfs存储和下载过程
- 【算法day5】排序算法的稳定性及其汇总
稳定性 定义:值相同的元素在排序完成之后能否保证原有的次序不变(同样值的个体之间,如果不因为排序而改变相对次序,这个排序就是有稳定性的,否则就没有) 举例: [2,1,3,1]-->[1,1,2 ...
- 【Azure 服务总线】查看Service Bus中消息多次发送的日志信息,消息是否被重复消费
问题描述 使用Service Bus,发现消息被重复消费.如果要查看某一条消息的具体消费情况,需要那些消息的属性呢? 问题解答 使用Azure Service Bus,当消费发送到服务端后,就会生产相 ...
- 【Azure 应用服务】App Service For Linux 怎么安装Composer,怎么安装PHP扩展,怎么来修改站点根路径启动程序?
问题一:App Service 的默认启动路径为wwwroot,如何修改到到PHP代码运行目录呢? 如Laravel的启动目录为public/?那如何修改呢? App Service 的默认 PHP ...
- java中StringBuffer与 StringBuilder 类
目录 创建 StringBuffer 类 追加字符串 替换字符 反转字符串 删除字符串 StringBuffer 方法 在 Java 中,除了通过 String 类创建和处理字符串之外,还可以使用 S ...
- centos7通过配置hosts.allow和hosts.deny限制登陆
etc/hosts.allow和/etc/hosts.deny两个文件是控制远程访问设置的,通过他可以允许或者拒绝某个ip或者ip段的客户访问linux的某项服务. 我们通常只对管理员开放SSH登录, ...
- 2023 Gartner RPA魔力象限报告解读:国产厂商“破纪录”跃升意味着什么?
2023 Gartner RPA魔力象限报告解读:象限跃升彰显国产RPA厂商实力 2023 Gartner RPA魔力象限报告四大行业趋势,国产RPA厂商已在践行 文/王吉伟 8月3日,全球著名咨询调 ...