题目大意:给你一棵树,点有点权$a_{i}$,边有边权$w_{e}$,定义一种路径称为$2-path$,每条边最多经过2次且该路径的权值为$\sum _{x} a_{x}\;-\;\sum_{e}w_{e}\cdot k_{e}$,$k_{e}$为边的经过次数,一共$Q$次询问,每次查询经过$x,y$的$2-path$权值最大的路径的权值

看题解之前感觉不可做...有点思路但感觉不靠谱,都被我否掉了

LiGuanlin神犇提供了一种树形DP的解法

定义$f[x][0]$表示该子树内,经过$x$点的$2path$路径的最大权值$-a[x]$的值

$f[x][1]$表示x点父树的子树内,不经过$x$点的路径的最大权值

$f[x][2]$表示该节点从父节点过来的$2path$路径的最大权值

$dfs$2次搜出$f$,再维护前缀和,转移即可

注意当倍增$lca$来找到$lca(x,y)$最靠近$x$的儿子,如果它在$f[lca(x,y)]$最优状态里,需要去掉它个贡献

 #include <cstdio>
#include <cstring>
#include <algorithm>
#define N 301000
#define uint unsigned int
#define ll long long
#define mod 1000000007
using namespace std; int gint()
{
int ret=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*f;
}
int n,q,cte;
int a[N],fe[N],fa[N],head[N];
ll f[N][],g[N][],vsum[N],esum[N];
struct Edge{int to,nxt,val;}edge[N*];
void ae(int u,int v,int w){
cte++;edge[cte].to=v,edge[cte].val=w;
edge[cte].nxt=head[u],head[u]=cte;
}
int use[N],dep[N];
ll dis[N],sum[N];
int ff[N][];
void dfs1(int u,int dad)
{
ff[u][]=u;
for(int j=head[u];j;j=edge[j].nxt){
int v=edge[j].to;
if(v==dad) continue;
dep[v]=dep[u]+,fa[v]=u,ff[v][]=u,fe[v]=edge[j].val;
dis[v]=dis[u]+edge[j].val;
vsum[v]=vsum[u]+a[v];
esum[v]=esum[u]+edge[j].val;
dfs1(v,u);
if(f[v][]+a[v]-2ll*edge[j].val>)
use[v]=,f[u][]+=f[v][]+a[v]-2ll*edge[j].val;
}
}
void dfs2(int u)
{
for(int j=head[u];j;j=edge[j].nxt){
int v=edge[j].to;
if(v==fa[u]) continue;
if(use[v]){
f[v][]=f[u][]-(f[v][]+a[v]-2ll*edge[j].val);
f[v][]=max(0ll,f[u][]+f[v][]+a[u]-2ll*edge[j].val);
}else{
f[v][]=f[u][];
f[v][]=max(0ll,f[u][]+f[v][]+a[u]-2ll*edge[j].val);
}
g[v][]=g[u][]+f[v][];
g[v][]=g[u][]+f[v][];
dfs2(v);
}
}
void get_lca()
{
for(int j=;j<=;j++)
for(int i=;i<=n;i++)
ff[i][j]=ff[ ff[i][j-] ][j-];
}
int Lca(int x,int y,int &fx,int &fy)
{
int px=x,py=y,ans,dx,dy,flag=;
if(dep[x]<dep[y]) swap(x,y);
for(int i=;i>=;i--)
if(dep[ff[x][i]]>=dep[y]) x=ff[x][i];
for(int i=;i>=;i--)
if(ff[x][i]!=ff[y][i]) x=ff[x][i],y=ff[y][i];
else ans=ff[x][i];
x=px,y=py;
dx=dep[ans]+;
dy=dep[ans]+;
for(int i=;i>=;i--){
if(dep[ff[x][i]]>=dx) x=ff[x][i];
if(dep[ff[y][i]]>=dy) y=ff[y][i];
}fx=x,fy=y;
return ans;
}
ll solve(int x,int y)
{
if(x==y) return f[x][]+f[x][]+a[x];
else if(fa[x]==y) return f[x][]+f[x][]+f[y][]+a[x]+a[y]-fe[x];
else if(fa[y]==x) return f[y][]+f[y][]+f[x][]+a[x]+a[y]-fe[y];
int fx,fy,lca;
lca=Lca(x,y,fx,fy);
ll ans=;
ans+=(vsum[x]+vsum[y]-vsum[lca]-vsum[fa[lca]])-(esum[x]+esum[y]-2ll*esum[lca]);
ans+=f[x][]+f[y][];
if(y==fy&&x!=fx){
ans+=g[x][]+g[y][]-2ll*g[lca][]-f[fx][];
if(use[fx]) ans-=f[fx][]+a[fx]-2ll*fe[fx];
}else{
ans+=g[x][]+g[y][]-2ll*g[lca][]-f[fy][];
if(use[fy]) ans-=f[fy][]+a[fy]-2ll*fe[fy];
}
ans+=f[lca][];
return ans;
} int main()
{
scanf("%d%d",&n,&q);
int x,y,w;
for(int i=;i<=n;i++)
a[i]=gint();
for(int i=;i<n;i++)
x=gint(),y=gint(),w=gint(),ae(x,y,w),ae(y,x,w);
dep[]=;
vsum[]=a[],dfs1(,-);
g[][]=f[][],dfs2();
get_lca();
for(int i=;i<=q;i++)
x=gint(),y=gint(),printf("%lld\n",solve(x,y));
return ;
}

CF1000G Two-Paths (树形DP)的更多相关文章

  1. Codeforces Beta Round #14 (Div. 2) D. Two Paths 树形dp

    D. Two Paths 题目连接: http://codeforces.com/contest/14/problem/D Description As you know, Bob's brother ...

  2. SPOJ6717 Two Paths 树形dp

    首先有朴素的\(O(n^2)\)想法 首先枚举断边,之后对于断边之后的两棵子树求出直径 考虑优化这个朴素的想法 考虑换根\(dp\) 具体而言,首先求出\(f[i], fs[i]\)表示\(i\)号点 ...

  3. 牛客第八场 C-counting paths 树形dp计数

    题目地址 题意 给你一颗树 初始点颜色全部为白色 对于每一个满足要求一的点集s f(s)的定义为先把点集内的点染黑 满足要求二的路径集合数量 要求一为两两黑点之间不能出现白色的点 要求二为将这个路径集 ...

  4. Codeforces Beta Round #14 (Div. 2) Two Paths (树形DP)

    Two Paths time limit per test 2 seconds memory limit per test 64 megabytes input standard input outp ...

  5. HDU4003Find Metal Mineral[树形DP 分组背包]

    Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Other ...

  6. CF 337D Book of Evil 树形DP 好题

    Paladin Manao caught the trail of the ancient Book of Evil in a swampy area. This area contains n se ...

  7. hdu 4003 Find Metal Mineral 树形DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal miner ...

  8. poj3162(树形dp+优先队列)

    Walking Race Time Limit: 10000MS   Memory Limit: 131072K Total Submissions: 5409   Accepted: 1371 Ca ...

  9. POJ 3162.Walking Race 树形dp 树的直径

    Walking Race Time Limit: 10000MS   Memory Limit: 131072K Total Submissions: 4123   Accepted: 1029 Ca ...

随机推荐

  1. IPv6特性,以及SLAAC过程

    1. IPv6特性 支持即插即用: 路由器发现(Router Discovery):当一个节点连接到一个IPv6的链路上时,它能够发现本地的路由器,而不必借助动态主机配置协议(DHCP). 前缀发现( ...

  2. day06-2 基本运算符(解压缩)

    目录 运算符 算数运算符 比较运算符 赋值运算符 逻辑运算符 运算规则 成员运算符 身份运算符 Python运算符优先级 链式赋值(必考) 交叉赋值(必考) 解压缩(必考) 运算符 算数运算符 进行算 ...

  3. ajax中遇到无法发送的问题,以及收不到返回信息的问题

    1.在做ajax时,数据发送成功,后台确认了也返回了信息,但是怎么都在success里面接收不了,我遇见的造成的原因时因为dataType返回值类型错误造成的原因. var url = "请 ...

  4. C#追加、拷贝、删除、移动文件、创建目录、递归删除文件夹及文件

    C#追加文件 StreamWriter sw = File.AppendText(Server.MapPath(".")+"\\myText.txt"); sw ...

  5. 分清encodeURIComponent encodeURI 和 escape

    encodeURIComponent encodeURI escape 目的:这三个函数的作用都是让一段字符串在所有电脑(所有国家区域语言)上可读. escape对字符串进行处理: encodeURI ...

  6. h5性能优化,细节决定结果。

    介绍一些最近整理的优化细节.图片压缩什么的就不说了,这是优化必须做的.今天就说一下大家写代码时可以培养的优化的细节点. 不滥用float.不滥用web字体. Float在渲染时计算量比较大,并且会脱标 ...

  7. 论文阅读《ActiveStereoNet:End-to-End Self-Supervised Learning for Active Stereo Systems》

    本文出自谷歌与普林斯顿大学研究人员之手并发表于计算机视觉顶会ECCV2018.本文首次提出了应用于主动双目立体视觉的深度学习解决方案,并引入了一种新的重构误差,采用自监督的方法来解决缺少ground ...

  8. [luogu] P4155 [SCOI2015]国旗计划(贪心)

    P4155 [SCOI2015]国旗计划 题目描述 A 国正在开展一项伟大的计划 -- 国旗计划.这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈.这项计划需要多名边防战士以接力的形式共同完成,为此 ...

  9. Golang-import-introduce

    本文主要讲解golang中import关键字的用法 import( "fmt" ) //然后在代码里面可以通过如下的方式调用 fmt.Println("hello wor ...

  10. APP热更新方案(转)

    本文转载自[http://creator.cnblogs.com/] 博客地址:Zealot Yin 为什么要做热更新 当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就 ...