题目大意:给你一棵树,其中点上和边上都有值。定义2-Path为经过一条边最多两次的路径,价值为经过点的权值加和-经过边权值*该边经过次数。4e5组询问,每次询问树上连接x,y两点的2-Path的最大价值。

先说一句:

机房中认为图画的最好:https://blog.csdn.net/lleozhang/article/details/83659914

题解:

一道状态比较多的树形dp。

dp1:记录x点子树内从x到x的最大2-Path的价值-x的值。

dp2:记录从fa[x]到fa[x]不经过x且不经过fa[fa[x]]的最大2-Path价值-fa[x]的值。

dp3:记录从fa[x]到fa[x]不经过x的任意儿子的2-Path的价值-x的值。

(描述比较恶心,见图)

(图也比较恶心)

红色的边和涂黑的未知物体都要取。

然后还有比较大众的ds1:记录x到根的点权之和,和ds2:记录x到根的边权之和。

还要求一下每个点到根节点经过点的dp2之和。

dfsO(n)搞dp,询问O(nlogn)。

比描述和图片更恶心的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 300050
#define Q 400050
#define ll long long
int n,q,hed[N],cnt;
struct EG
{
int to,nxt;
ll val;
}e[*N];
void ae(int f,int t,ll v)
{
e[++cnt].to = t;
e[cnt].val = v;
e[cnt].nxt = hed[f];
hed[f] = cnt;
}
ll a[N];
int dep[N],fa[N][];
ll ds1[N],ds2[N],E[N];
void dfs1(int u,int f)
{
dep[u]=dep[f]+;
for(int j=hed[u];j;j=e[j].nxt)
{
int to = e[j].to;
if(to==f)continue;
fa[to][]=u;
E[to]=e[j].val;
ds1[to]=ds1[u]+a[to];
ds2[to]=ds2[u]+e[j].val;
dfs1(to,u);
}
}
int get_lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=;i>=;i--)
if(dep[fa[x][i]]>=dep[y])
x=fa[x][i];
if(x==y)return x;
for(int i=;i>=;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][];
}
ll dp1[N],dp2[N];
bool vis[N];
void dfs(int u)
{
for(int j=hed[u];j;j=e[j].nxt)
{
int to = e[j].to;
if(to==fa[u][])continue;
dfs(to);
if(dp1[to]+a[to]-2ll*e[j].val>=)
{
dp1[u]+=dp1[to]+a[to]-2ll*e[j].val;
vis[to]=;
}
}
for(int j=hed[u];j;j=e[j].nxt)
{
int to = e[j].to;
if(to==fa[u][])continue;
if(!vis[to])dp2[to]=dp1[u];
else dp2[to]=dp1[u]-(dp1[to]+a[to]-2ll*e[j].val);
}
}
ll dp3[N],sum2[N];
void Dfs(int u)
{
sum2[u]+=dp2[u];
for(int j=hed[u];j;j=e[j].nxt)
{
int to = e[j].to;
if(to==fa[u][])continue;
sum2[to]+=sum2[u];
dp3[to]=max(0ll,dp3[u]+1ll*a[u]+dp2[to]-2ll*e[j].val);
Dfs(to);
}
}
ll sol(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
int lca = get_lca(x,y);
if(x==lca)
{
return dp3[x]+dp1[y]+sum2[y]-sum2[x]+(ds1[x]+ds1[y]-ds1[lca]-ds1[fa[lca][]])-(ds2[x]+ds2[y]-2ll*ds2[lca]);
}else
{
int ffx = x,ffy = y;
for(int i=;i>=;i--)
{
if(dep[fa[ffx][i]]>dep[lca])
ffx=fa[ffx][i];
if(dep[fa[ffy][i]]>dep[lca])
ffy=fa[ffy][i];
}
return dp1[x]+dp1[y]+sum2[x]+sum2[y]-sum2[ffx]-sum2[ffy]+dp3[lca]+dp2[ffx]-(vis[ffy]==)*(dp1[ffy]+a[ffy]-2ll*E[ffy])+(ds1[x]+ds1[y]-ds1[lca]-ds1[fa[lca][]])-(ds2[x]+ds2[y]-2ll*ds2[lca]);
}
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=;i<=n;i++)scanf("%lld",&a[i]);
ll v;
for(int f,t,i=;i<n;i++)
{
scanf("%d%d%lld",&f,&t,&v);
ae(f,t,v),ae(t,f,v);
}
ds1[]=a[];
dfs1(,);
for(int k=;k<=;k++)
for(int i=;i<=n;i++)
fa[i][k]=fa[fa[i][k-]][k-];
dfs();
Dfs();
for(int x,y,i=;i<=q;i++)
{
scanf("%d%d",&x,&y);
printf("%lld\n",sol(x,y));
}
return ;
}

CF1000G Two-Paths的更多相关文章

  1. [LeetCode] Binary Tree Paths 二叉树路径

    Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...

  2. [LeetCode] Unique Paths II 不同的路径之二

    Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...

  3. [LeetCode] Unique Paths 不同的路径

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...

  4. leetcode : Binary Tree Paths

    Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...

  5. UVA 10564 Paths through the Hourglass[DP 打印]

    UVA - 10564 Paths through the Hourglass 题意: 要求从第一层走到最下面一层,只能往左下或右下走 问有多少条路径之和刚好等于S? 如果有的话,输出字典序最小的路径 ...

  6. LeetCode-62-Unique Paths

    A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The ...

  7. Leetcode Unique Paths II

    Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...

  8. POJ 3177 Redundant Paths(边双连通的构造)

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13717   Accepted: 5824 ...

  9. soj 1015 Jill's Tour Paths 解题报告

    题目描述: 1015. Jill's Tour Paths Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description Every ...

  10. Unique Paths II

    这题在Unique Paths的基础上增加了一些obstacle的位置,应该说增加的难度不大,但是写的时候对细节的要求多了很多,比如,第一列的初始化会受到之前行的第一列的结果的制约.另外对第一行的初始 ...

随机推荐

  1. 05_传智播客iOS视频教程_第一个OC程序

    Cocoa Application开发的是带界面的程序. OC是完全兼容C语言的,但是C语言里面是不能写OC的东西的. OC和C的第一个区别,就是源文件的后缀名的区别.OC程序的源文件的后缀名是.m, ...

  2. 转载:Eclipse build Android时不生成apk问题解决方法

    Eclisps有时build后不生成apk.没有对Eclise做过设置调整,android工程代码也是没有问题的.反正就是莫名奇妙的遇到两次,解决方法如下: 1. 设置:Preferences -&g ...

  3. bzoj 1606: [Usaco2008 Dec]Hay For Sale 购买干草【01背包】

    在洛谷上被卡常了一个点! 就是裸的01背包咯 为啥我在刷水题啊 #include<iostream> #include<cstdio> #include<algorith ...

  4. (6)css盒子模型(基础下)

    一.理解多个盒子模型之间的相互关系 现在大部分的网页都是很复杂的,原因是一个“给人用的”网页中是可能存在着大量的盒子,并且它们以各种关系相互影响着. html与DOM的关系 详情了解“DOM” :ht ...

  5. [App Store Connect帮助]八、维护您的 App(5)生成产品报告

    您可以生成产品报告,详细介绍您所在机构中 App 目录的信息和设置,包括 App 内购买项目,以及 Game Center排行榜和成就的元数据. 首先您以不同类型请求产品报告,之后您会收到一封电子邮件 ...

  6. Luogu P2735 电网【真·计算几何/Pick定理】By cellur925

    题目传送门 刷USACO偶然遇到的,可能是人生中第一道正儿八经的计算几何. 题目大意:在平面直角坐标系中给你一个以格点为顶点的三角形,求三角形中的整点个数. 因为必修5和必修2的阴影很快就想到了数学中 ...

  7. 莫比乌斯反演总结——Chemist

    懵逼乌斯反演果然名不虚传,自闭了两天的我打算学习一下这一块比较实用的数论内容. (注:1.为了区分狄尼克雷卷积与乘法,本篇文章中乘号全部省略,卷积全部用" * "表示.2.用gcd ...

  8. Qt事件系统之三:键盘事件

    QKeyEvent类用来描述一个键盘事件.当键盘按键被按下或者被释放时,键盘事件便会被发送给拥有键盘输人焦点的部件. QKeyEvent的key()函数可以获取具体的按键,对于Qt中给定的所有按键,可 ...

  9. hbase源码分析:ERROR: Table already exists问题诊断

    问题描述: 重新安装了测试环境的hadoop,所以之前hbase所建的表数据都丢失了,但是zookeeper没有动.在hbase shell中list的时候,看不到之前建的表,但是create tes ...

  10. Zclip点击复制内容到剪贴板兼容各浏览器

    WEB开发中,要让用户复制页面中的一段代码.URL地址等信息,为了避免用户拖动鼠标再进行右键复制操作而可能出现的差错,我们可以直接在页面中放置一个复制按钮,只需要轻轻一点这个复制按钮,内容将会被复制, ...