原文链接https://www.cnblogs.com/zhouzhendong/p/9246484.html

题目传送门 - Codeforces 1000G Two-Paths

题意

  给定一棵有 $n(2\leq n\leq 3\times 10^5)$ 个节点的树,其中节点 $i$ 有权值 $a_i$,边 $e$ 有权值 $w_e$。$(1\leq a_i,w_e\leq 10^9)$

  现在给出 $q(1\leq q\leq 4\times 10^5)$ 组询问,每组询问给定两个数 $x,y(1\leq x,y\leq n)$。

  如果一条路径的起点和终点分别为 $x$ 和 $y$,而且这条路径重复经过同一条边最多 $2$ 次(点可以多次经过),那么这条路径合法。

  一条合法路径 $P$ 的价值为 $Pr(p)$。$\text{Pr}(p) = \sum\limits_{v \in \text{distinct vertices in } p}{a_v} - \sum\limits_{e \in \text{distinct edges in } p}{k_e \cdot w_e}$。

  其中 $k_e$ 为路径 $p$ 经过 $e$ 的次数。

  每次询问问所有合法路径的最大价值。

题解

  我们来跑一下树形dp。

  求出以下值。(下面是示意图,有填色的部分表示被计算)

  其中 $dp1,dp2,f1,sum$ 都表示所取的部分的合法最大值。

  

    

  

  再描述一下上面六个量的意义:

  dp1[x]:往 $x$ 的后代节点走最多可以赚多少。

  dp2[x]:往 $x$ 的祖先走最多可以赚多少。

  f1[x]:从 $x$ 的祖先向 $x$ 走最多可以赚多少。

  sum[x]:令树根到 $x$ 父亲的链为主链,假设主链上行走没有任何消耗和获益,向主链走最多可以获益多少。

  len[x]:$x$ 到根的距离(带边权)。

  s[x]:$x$ 的深度。

  

  在回答询问 $x,y$ 的时候,首先从 $x$ 到 $y$ 的路径一定被选,其中的边一定只走一次。

  其他的我们根据之前维护的量分类讨论加加减减一下就可以了。

  详见代码。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=300005,M=N*2;
LL read(){
LL x=0;
char ch=getchar();
while (!('0'<=ch&&ch<='9'))
ch=getchar();
while ('0'<=ch&&ch<='9')
x=x*10+ch-48,ch=getchar();
return x;
}
struct Gragh{
int cnt,y[M],nxt[M],fst[N];
LL z[M];
void clear(){
cnt=0;
memset(fst,0,sizeof fst);
}
void add(int a,int b,LL c){
y[++cnt]=b,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
}
}g;
int n,q,fa[N][20],depth[N],xx,yy;
LL a[N],dp1[N],f1[N],dp2[N],sum[N],fadis[N],len[N],s[N];
void dfs1(int x,int pre,int d,LL L){
fa[x][0]=pre;
depth[x]=d;
len[x]=L;
s[x]=s[pre]+a[x];
for (int i=1;i<20;i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
dp1[x]=0;
for (int i=g.fst[x];i;i=g.nxt[i]){
int y=g.y[i];
LL z=g.z[i];
if (y!=pre){
dfs1(y,x,d+1,L+z);
fadis[y]=z;
f1[y]=max(dp1[y]+a[y]-z*2,0LL);
dp1[x]+=f1[y];
}
}
}
void dfs2(int x,int pre,LL v,LL v2){
dp2[x]=v;
sum[x]=v2;
for (int i=g.fst[x];i;i=g.nxt[i]){
int y=g.y[i];
LL z=g.z[i];
if (y!=pre){
LL _v=max(v+a[x]+dp1[x]-f1[y]-2*z,0LL);
LL _v2=max(v2+dp1[x]-f1[y],0LL);
dfs2(y,x,_v,_v2);
}
}
}
int LCA(int x,int y){
if (depth[x]<depth[y])
swap(x,y);
for (int i=19;i>=0;i--)
if (depth[x]-(1<<i)>=depth[y])
x=fa[x][i];
if (x==y)
return x;
for (int i=19;i>=0;i--)
if (fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
xx=x,yy=y;
return fa[x][0];
}
int main(){
scanf("%d%d",&n,&q);
for (int i=1;i<=n;i++)
a[i]=read();
g.clear();
for (int i=1;i<n;i++){
int a=read(),b=read();
LL c=read();
g.add(a,b,c);
g.add(b,a,c);
}
dfs1(1,0,0,0);
dfs2(1,0,0,0);
while (q--){
int x,y,lca;
scanf("%d%d",&x,&y);
if (depth[x]>depth[y])
swap(x,y);
lca=LCA(x,y);
if (x==lca){
if (y==lca){
printf("%I64d\n",dp1[x]+dp2[x]+a[x]);
continue;
}
LL ans=s[y]-s[x]+a[x];
ans-=len[y]-len[x];
ans+=sum[y]-sum[x];
ans+=dp2[x]+dp1[y];
printf("%I64d\n",ans);
continue;
}
LL ans=s[x]+s[y]-s[lca]*2+a[lca];
ans-=len[x]+len[y]-len[lca]*2;
ans+=sum[x]+sum[y]-sum[xx]-sum[yy];
ans+=dp1[lca]-f1[xx]-f1[yy];
ans+=dp2[lca]+dp1[x]+dp1[y];
printf("%I64d\n",ans);
}
return 0;
}

  

Codeforces 1000G Two-Paths 树形动态规划 LCA的更多相关文章

  1. 蓝桥杯 ALGO-4 结点选择 (树形动态规划)

    问题描述 有一棵 n 个节点的树,树上每个节点都有一个正整数权值.如果一个点被选择了,那么在树上和它相邻的点都不能被选择.求选出的点的权值和最大是多少? 输入格式 第一行包含一个整数 n . 接下来的 ...

  2. 树形动态规划(树状DP)小结

    树状动态规划定义 之所以这样命名树规,是因为树形DP的这一特殊性:没有环,dfs是不会重复,而且具有明显而又严格的层数关系.利用这一特性,我们可以很清晰地根据题目写出一个在树(型结构)上的记忆化搜索的 ...

  3. Codeforces 581F Zublicanes and Mumocrates - 树形动态规划

    It's election time in Berland. The favorites are of course parties of zublicanes and mumocrates. The ...

  4. 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 ...

  5. Codeforces 839C Journey - 树形动态规划 - 数学期望

    There are n cities and n - 1 roads in the Seven Kingdoms, each road connects two cities and we can r ...

  6. Codeforces Round #343 (Div. 2) E. Famil Door and Roads (树形dp,lca)

    Famil Door's City map looks like a tree (undirected connected acyclic graph) so other people call it ...

  7. LEETCODE —— Unique Paths II [动态规划 Dynamic Programming]

    唯一路径问题II Unique Paths II Follow up for "Unique Paths": Now consider if some obstacles are ...

  8. Codeforces Gym 100015C City Driving 离线LCA

    City Driving 题目连接: http://codeforces.com/gym/100015/attachments Description You recently started fre ...

  9. 【ACM/ICPC2013】树形动态规划专题

    前言:按照计划,昨天应该是完成树形DP7题和二分图.最大流基础专题,但是由于我智商实在拙计,一直在理解树形DP的思想,所以第二个专题只能顺延到今天了.但是昨天把树形DP弄了个5成懂我是很高兴的!下面我 ...

随机推荐

  1. Java中instanceof与getClass的区别

    在比较一个类和另一个类是否属于同一个类实例的时候,通常可以采用instanceof和getClass两种方法比较两者是否相等来判断,但是两者在判断上面是有差别的,下面通过代码说明: public cl ...

  2. python 函数 动态参数 和嵌套

    1.动态参数 是可以接收任意的参数.一种方式, 1,位置的动态传参, 写法是: *参数名 接收的参数是tuple类型举个例子:def yue(*food): print(food)yue(" ...

  3. 解决定位工具报错Error while parsing UI hierarchy XML file: Invalid ui automator hierarchy file.

    在微信自动化测试中,偶尔会出现某个页面一直无法读取到页面元素的情况,原因是页面未加载完成 解决方式:1.重启APP 2.建议上下滑动当前页面,如朋友圈,会出现滑动到某个地方,出现可以读取到的情况 参考 ...

  4. Nginx(./configure --help)

    # ./configure --help --help print this message --prefix=PATH set installation prefix --sbin-path=PAT ...

  5. |"|&|<|>等html字符转义

    本文来源:d4shman  <&nbsp|&quot|&amp|&lt|&gt等html字符转义> 提示:请直接按CTRL+F搜索您要查找的转义字符 ...

  6. Confluence 6 生产环境备份策略

    如果你是下面的情况,Confluence 的自动每日 XML 备份可能适合你: 正在评估使用 Confluence 你对数据库的管理并不是非常熟悉同时你的 Confluence 安装实例的数据量并不大 ...

  7. SWift中 '?' must be followed by a call, member lookup, or subscript 错误解决方案

    那是因为你在使用自己写的分类时没有指定返回的数据类型  指定下返回数据类型就好了 我是用的oc写的分类在Swift中使用的 错误代码 private lazy var btn = UIButton.C ...

  8. Java之动手动脑(三)

    日期:2018.10.12 星期五 博客期:017 这次留了两个动手动脑作业!我需要一个一个来说!先说第一个吧! Part 1 :随机生成1000个随机数 代码: //以下为 RandomMaker. ...

  9. 使用gulp-babel转换Es6出现exports is not defined 问题

    //问题描述:当使用import导入模块时,出现exports is not defined //1.安装插件 npm install --save-dev babel-plugin-transfor ...

  10. swoole 简介