题目大意:给你一棵树,点有点权$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. 这个夏天有你,有CorelDRAW X7,有理想,有设计!

    CorelDRAW是加拿大Corel公司出品的一款功能全面的矢量绘图.平面设计软件,兼有图形设计的简易操作性和图像编辑的强大功能.目前,被广泛应用于广告宣传.艺术作品.纺织业等各个行业.和Photos ...

  2. Cookie和Session有什么区别

    1. 由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是Session.   典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状 ...

  3. HDU 5289 Assignment [优先队列 贪心]

    HDU 5289 - Assignment http://acm.hdu.edu.cn/showproblem.php?pid=5289 Tom owns a company and he is th ...

  4. Element源码阅读(1)

    一.目的 阅读element源码旨在了解其代码的组织架构模式, 代码编写的方式, 以及组件化的一些思路, 对照自己, 从而进步. 二. 源码阅读所得 1.在element源码中的mixins目录之下, ...

  5. DOM元素属性值如果设置为对象

    结论:内部会调用toString方法,将设置的对象转换为字符串添加给相应的属性: 这个问题呢,是通过jQuery的each方法中,回调函数的this指向问题而来: 我们知道,回调函数中的this如果指 ...

  6. [USACO 2009 Feb Gold] Fair Shuttle (贪心+优先队列)

    题目大意:有N个站点的轻轨站,有一个容量为C的列车起点在1号站点,终点在N号站点,有K组牛群,每组数量为Mi(1≤Mi≤N),行程起点和终点分别为Si和Ei(1≤Si<Ei≤N).计算最多有多少 ...

  7. HBase入门操作 常用命令和增删改查的简单应用操作

    这里启动关闭Hadoop和HBase的顺序一定是: 启动Hadoop—>启动HBase—>关闭HBase—>关闭Hadoop ssh localhost 开启hadoopcd /us ...

  8. Lvs+heartbeat高可用高性能web站点的搭建

    这是我们公司在实际的生产环境当中使用的一套东西,希望对大家有所帮助(实际的公网ip,我已经做了相应的修改): 说明:每台服务器需要有两块网卡:eth0连接内网的交换机,用私网ip,实现服务器间内部访问 ...

  9. 设置PATH 环境变量、pyw格式、命令行运行python程序与多重剪贴板

    pyw格式简介: 与py类似,我认为他们俩卫衣的不同就是前者运行时候不显示终端窗口,后者显示 命令行运行python程序: 在我学习python的过程中我通常使用IDLE来运行程序,这一步骤太过繁琐( ...

  10. typedef和define混用产生的错误

    最近在写代码过程中,发现一个问题,编译总是过不去,报错如下: stdint.h::: error: duplicate 'unsigned' stdint.h::: error: 'long long ...