题目

给定一棵树,边权是整数 \(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 树的双直径的更多相关文章

  1. 51nod 1812 树的双直径 题解【树形DP】【贪心】

    老了-稍微麻烦一点的树形DP都想不到了. 题目描述 给定一棵树,边权是整数 \(c_i\) ,找出两条不相交的链(没有公共点),使得链长的乘积最大(链长定义为这条链上所有边的权值之和,如果这条链只有 ...

  2. 51nod1812树的双直径(换根树DP)

    传送门:http://www.51nod.com/Challenge/Problem.html#!#problemId=1812 题解:头一次写换根树DP. 求两条不相交的直径乘积最大,所以可以这样考 ...

  3. LOJ2250 [ZJOI2017] 仙人掌【树形DP】【DFS树】

    题目分析: 不难注意到仙人掌边可以删掉.在森林中考虑树形DP. 题目中说边不能重复,但我们可以在结束后没覆盖的边覆盖一个重复边,不改变方案数. 接着将所有的边接到当前点,然后每两个方案可以任意拼接.然 ...

  4. hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。

    /** 题目:hdu6035 Colorful Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:给定一棵树,每个节点有一个颜色值.定 ...

  5. 51nod"省选"模测 A 树的双直径(树形dp)

    题意 题目链接 Sol 比赛结束后才调出来..不多说啥了,就是因为自己菜. 裸的up-down dp,维护一下一个点上下的直径就行,一开始还想了个假的思路写了半天.. 转移都在代码注释里 毒瘤题目卡空 ...

  6. hdu 2196(方法1:经典树形DP+方法2:树的直径)

    Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  7. 【洛谷】2607: [ZJOI2008]骑士【树形DP】【基环树】

    P2607 [ZJOI2008]骑士 题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一 ...

  8. HDU4612(Warm up)2013多校2-图的边双连通问题(Tarjan算法+树形DP)

    /** 题目大意: 给你一个无向连通图,问加上一条边后得到的图的最少的割边数; 算法思想: 图的边双连通Tarjan算法+树形DP; 即通过Tarjan算法对边双连通缩图,构成一棵树,然后用树形DP求 ...

  9. 【BZOJ-2286】消耗战 虚树 + 树形DP

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2120  Solved: 752[Submit][Status] ...

  10. BZOJ5287 HNOI2018毒瘤(虚树+树形dp)

    显然的做法是暴力枚举非树边所连接两点的选或不选,大力dp.考场上写的是最暴力的O(3n-mn),成功比大众分少10分.容斥或者注意到某些枚举是不必要的就能让底数变成2.但暴力的极限也就到此为止. 每次 ...

随机推荐

  1. win32 - WM_DROPFILES的用法

    WM_DROPFILES: 当用户将文件拖放到已注册为丢弃文件的接收者的应用程序窗口中时发送该消息 我们可以利用这个消息获取文件名称,并将它们保存到容器里. LRESULT CALLBACK Stat ...

  2. 服务端高性能网络IO编程模型简析

    服务端高性能网络IO编程模型简析 一.客户端与服务器端 多数网络应用可以分为客户端(client)和服务器端(server)模型,然后中间通过各种定义的协议来进行两端的通信. 比如常用的 Nginx ...

  3. Mysql 删除binlog日志方法

    方法1 RESET MASTER; 解释: 该方法可以删除列于索引文件中的所有二进制日志,把二进制日志索引文件重新设置为空,并创建一个以.000001为后缀新的二进制日志文件. 该语法一般只用在主从环 ...

  4. com.fasterxml.jackson.databind.exc.InvalidDefinitionException

    @JsonIgnoreProperties 此注解是类注解,作用是json序列化时将Java bean中的一些属性忽略掉,序列化和反序列化都受影响. 写法将此标签加在model 类的类名上 ,可以多个 ...

  5. 大众点评cat报警源码

    类时序 时许说明 判断是否是报警机器. 1分钟启动一个线程根据设置的报警条件,时间段去查询CAT报告数据. 根据返回的报告数据,逐层解析TYPE,NAME,RANGE中的数据是否满足报警条件. 只有全 ...

  6. 【Azure 应用程序见解】通过无代码方式在App Service中启用Application Insights后,如何修改在Application Insights中显示的App Service实例名呢?

    问题描述 在App Service中,可以非常容易的启动Application Insights服务.默认情况中,在Application Insights中查看信息时候,其中的对象名称默认为App ...

  7. STL-unordered_map,unordered_set模拟实现

    unordered_set #pragma once #include"28hashtable_container.h" namespace test { //template & ...

  8. Java 线程通信的应用:经典例题:生产者/消费者问题

    1 package bytezero.threadcommunication; 2 3 /** 4 * 线程通信的应用:经典例题:生产者/消费者问题 5 * 6 * 7 * 8 * @author B ...

  9. Dubbo基本见解

    1.dubbo主要角色 Provider: 暴露服务的服务提供方. Consumer: 调用远程服务的服务消费方. a.订阅注册中心,注册中心广播服务变更,第一次会主动全量pull所有信息,后面增量会 ...

  10. springboot参数据校验

    什么是Hibernate Validator? Hibernate Validator是Hibernate提供的一个开源框架,使用注解方式非常方便的实现服务端的数据校验. 官网:http://hibe ...