原文链接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. python学习第天14天。

    模块 什么是模块 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代码( ...

  2. RedHat Linux关闭防火墙的命令

    获得root 控制权限.在“#”下操作. 查看防火墙状态. systemctl status firewalld 临时关闭防火墙命令.重启电脑后,防火墙自动起来. systemctl stop fir ...

  3. oracle user locked(timed)处理

    故障现象: SQL> connect scott/scottERROR:ORA-01017: invalid username/password; logon deniedSQL> con ...

  4. 通过设置ie的通过跨域访问数据源,来访问本地服务

    1.首先设置通过域访问数据源 设置通过域访问数据源 2.javascript脚本ajax使用本地服务登录(评价,人证的类似)接口 <html> <head> <scrip ...

  5. Confluence 6 订阅所应用的所有小工具

    你可以从你的 Jira, Bamboo,FishEye 或 Crucible 站点中订阅所有的小工具到你的 Confluence 小工具目录中.用户可以为他们的页面查找和选择小工具. 希望订阅其他站点 ...

  6. linux下命令窗口中$和#的区别

    $表示现在的用户是普通用户#表示现在的用户是root用户 # 代表你能做任何事$ 代表你能做一些/下和/home目录的所有事

  7. Java 并发类

    java.util.concurrent包里 提供了一批线程安全的类 一. java.util.concurrent.atomic java.util.concurrent.atomic包里的原子处理 ...

  8. swoole 简介

  9. Allegro PCB Design GXL (legacy) 手动更改元器件引脚的网络

    Allegro PCB Design GXL (legacy) version 16.6-2015 1.菜单:Setup > User Preferences... 2.User Prefere ...

  10. 远程执行shell脚本

    ssh -p2016 apache@10.10.18.130 '/bin/sh /data/www/vhosts/WOStest3_ENV/update_env.sh' 需要设置shell远程免密码登 ...