题意 : 给出一颗树,每条边有过路费,每个点有价值
定义一种名叫tow-path的路径 这种路径上 每条边可以经过最多两次
路径的权值为:
既路径上所有经过的点的权值和减去过路费之和;
现在有q次询问 每次询问给出两个点u,v 。
对于每次询问 要求输出u到v的tow-path 最大权值。
解题思路:
首先,看见这题应该要联想到 求树上两点路径长度 这一经典问题。
考虑是否可以套用这种方法。
定义 tofa[i] 表示 i节点到根节点的tow- path 的最大价值。
考虑是否能够通过dp 在O(n)的时间内求出这个状态
直接转移显然不好转移。
那么,在考虑这种问题的最简情况,既 只有一个点的情况。
定义toson[i] 表示以i为起点和终点的最大价值tow-path
显然 求toson数组是一个很经典的DP问题,两遍dfs即可。
求出toson后 就可以通过toson来得到tofa。 也是很好想到的。
那么这道题差不多就做完了。
细节看代码。
#include<bits/stdc++.h>
using namespace std;
const int MAX=3e5+10;
class Edge{
public:
int v,next;
long long w;
};
int n;
int tot;
int head[MAX];
Edge edge[MAX<<1];
long long values[MAX];
void init(){
memset(head,-1,sizeof head);
tot=0;
}
void add(int u,int v,int w){
edge[tot].v=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot;
tot++;
}
long long toson[MAX];// 以i为节点的子树 以i为起点和终点 走tow-path的最大价值
void dfs1(int u,int pre){
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==pre){
continue;
}
dfs1(v,u);
toson[u]+=max(0ll,toson[v]-edge[i].w*2);
}
toson[u]+=values[u];
}
long long tofa[MAX];
void dfs2(int u,int pre){
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==pre){
continue;
}
tofa[v]=toson[v]+tofa[u]-max(0ll,toson[v]-edge[i].w*2)-edge[i].w;
toson[v]+=max(0ll,toson[u]-max(0ll,toson[v]-edge[i].w*2)-2*edge[i].w);
dfs2(v,u);
}
}
//<----------------------------- LCA -------------------------------->
int deep[MAX];
int fa[MAX][23];
int dfs3(int u,int _deep,int _fa){
deep[u]=_deep;
fa[u][0]=_fa;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==_fa){
continue;
}
dfs3(v,_deep+1,u);
}
}
void presove(){
dfs3(1,0,1);
for(int i=1;i<=20;i++){
for(int j=1;j<=n;j++){
fa[j][i]=fa[fa[j][i-1]][i-1];
}
}
}
int LCA(int u,int v){
while(deep[u]!=deep[v]){
if(deep[u]<deep[v]){
swap(u,v);
}
int d= deep[u] -deep[v];
for(int i=0;i<=20;i++){
if(d>>i &1) u=fa[u][i];
}
}
if(u==v) return u;
for(int i=20;i>=0;i--){
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
}
return fa[u][0];
}
int main(){
int q;
scanf("%d %d",&n,&q);
init();
for(int i=1;i<=n;i++){
scanf("%lld",&values[i]);
}
for(int i=1;i<n;i++){
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dfs1(1,-1);
dfs2(1,-1);
presove();
while(q--){
int u,v;
scanf("%d %d",&u,&v);
int fas=LCA(u,v);
printf("%lld\n",tofa[u]+tofa[v]-2ll*tofa[fas]+toson[fas]);
}
}