题目大意:给你一棵树,点有点权$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. 转载:Vim 配置入门

    转载:Vim 配置入门 原文地址:http://www.ruanyifeng.com/blog/2018/09/vimrc.html 作者: 阮一峰 Vim 是最重要的编辑器之一,主要有下面几个优点. ...

  2. 使用node+mysql进行后端开发

    使用koa: koa2是一个类,所以引入koa后,要创建实例化“对象”,才能使用koa内部封装的方法. 设置监听端口: 处理http请求: 1.http请求处理链 A.通过app.use()注册asy ...

  3. BZOJ4545: DQS的trie 广义后缀自动机_LCT

    特别鸣神犇 fcwww 替我调出了无数个错误(没他的话我都快自闭了),祝大佬省选rp++ 板子题,给我写了一天QAQ...... 用 LCT 维护后缀树,暴力更新用 LCT 区间更新链即可 其实,在计 ...

  4. JS 日历

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx. ...

  5. BZOJ 2118 墨墨的等式 (同余最短路)

    题目大意:已知B的范围,求a1x1+a2x2+...+anxn==B存在非负正整数解的B的数量,N<=12,ai<=1e5,B<=1e12 同余最短路裸题 思想大概是这样的,我们选定 ...

  6. BZOJ 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)

    题目大意:维护一个字符串,支持插入字符和替换字符的操作,以及查询该字符串两个后缀的最长公共前缀长度 乍一看以为是后缀数组,然而并没有可持久化后缀数组(雾) 看题解才知道这是一道splay题,首先要对s ...

  7. Python学习笔记(一):基本数据类型

    在Python3种,有六种标准数据类型: 数字(Number) 字符串(String) 列表(List) 元组(Tuple) 集合(Set) 字典(Dictionary) 这六种数据类型中,数字类型和 ...

  8. DQL查询语句使用(select)

      9)DQL查询语句使用   SELECT语句在PL/SQL中使用,必须 采用下面用法:     select id INTO 变量   from t001 where id=5;    将记录字段 ...

  9. 机器学习之&amp;&amp;Andrew Ng课程复习--- 聚类——Clustering

    第十三章.聚类--Clustering ******************************************************************************** ...

  10. 【万里征程——Windows App开发】控件大集合2

    以下再来看看一些前面还没有讲过的控件,只是控件太多以至于无法所有列出来,大家仅仅好举一反三啦. Button 前面最经常使用的控件就是Button啦,Button另一个有意思的属性呢.当把鼠标指针放在 ...