Codeforces 1000G Two-Paths 树形动态规划 LCA

原文链接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。

  求出以下最大贡献值。(下面是示意图,有填色的部分表示被计算)

  

代码

#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;
}

  

原文地址:https://www.cnblogs.com/zhouzhendong/p/9246484.html

时间: 2024-10-11 22:21:18

Codeforces 1000G Two-Paths 树形动态规划 LCA的相关文章

Facebook Hacker Cup 2015 Round 1--Corporate Gifting(树形动态规划)

原题:https://www.facebook.com/hackercup/problems.php?pid=759650454070547&round=344496159068801 题意:给定一颗有根树,在树上下层的节点要给上层节点礼物,根节点的礼物则给慈善会,但是给礼物有个条件就是你不能送你的父节点已经送出的礼物.问满足要求的最少花费. 题解:这个题卡了一段时间,类似于染色问题,可以用树形动态规划求解.因为已知节点个数为N,则我们单个节点的最大花费不会超过log2(N) = 18. 1.

树形动态规划

问题可以分解成若干相互联系的阶段,在每一个阶段都要做出决策,全部过程的决策是一个决策序列.要使整个活动的总体效果达到最优的问题,称为多阶段决策问题.动态规划就是解决多阶段决策最优化问题的一种思想方法. 阶段 将所给问题的过程,按时间或空间特征分解成若干相互联系的阶段,以便按次序去求每阶段的解 状态 各阶段开始时的客观条件叫做状态. 决策 当各段的状态取定以后,就可以做出不同的决定,从而确定下一阶段的状态,这种决定称为决策. 策略 由开始到终点的全过程中,由每段决策组成的决策序列称为全过程策略,简

树形动态规划练习《蓝桥杯 结点选择》

问题描述 有一棵 n 个节点的树,树上每个节点都有一个正整数权值.如果一个点被选择了,那么在树上和它相邻的点都不能被选择.求选出的点的权值和最大是多少? 输入格式 第一行包含一个整数 n . 接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值. 接下来一共 n-1 行,每行描述树上的一条边. 输出格式 输出一个整数,代表选出的点的权值和的最大值. 样例输入 51 2 3 4 51 21 32 42 5 样例输出 12 样例说明 选择3.4.5号点,权值和为 3+4+5 = 12

Codeforces 14D Two Paths 树的直径

题目链接:点击打开链接 题意:给定一棵树 找2条点不重复的路径,使得两路径的长度乘积最大 思路: 1.为了保证点不重复,在图中删去一条边,枚举这条删边 2.这样得到了2个树,在各自的树中找最长链,即树的直径,然后相乘即可 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #includ

Codeforces 123E Maze(树形DP+期望)

[题目链接] http://codeforces.com/problemset/problem/123/E [题目大意] 给出一棵,给出从每个点出发的概率和以每个点为终点的概率,求出每次按照dfs序从起点到达终点的期望. [题解] 首先对于期望计算有X(x,y)=X(x)*X(y),所以对于每次dfs寻路只要求出其起点到终点的期望步数,乘上起点的概率和终点的概率即可.对于一个固定起点和终点的dfs寻路,我们可以发现如果一个点在必要路径上,那么这条路被走过的期望一定为1,如果不在必要路线上,那么走

【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树形dp/LCA/树的点分治

题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F1..F7表示, 每个农场最多能在东西南北四个方向连结4个不同的农场.此外,农场只处在道路的两端.道路不会交叉且每对农场间有且仅有一条路径.邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复了.每一条道路的信息如下: 从农场23往南经距离10到达农场17 从农场1往东经距离7到达农

leetcode_62题——Unique Paths (动态规划)

Unique Paths Total Accepted: 45580 Total Submissions: 138958My Submissions Question Solution A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below). The robot can only move either down or right at any point in

Codeforces 37D Lesson Timetable - 组合数学 - 动态规划

题目传送门 神奇的门I 神奇的门II 题目大意 有$n$组学生要上课2次课,有$m$个教室,编号为$1$到$m$.要确定有多少种不同的安排上课的教室的方案(每组学生都是本质不同的),使得它们满足: 每组学生第一次上课的教室的编号小于等于第二次上课的教室的编号. 第$i$间教室在第一次上课时,恰好有$x_{i}$组学生在场. 第$i$间教室在某次上课时,中间包含的学生组数不能超过$y_{i}$. 输出答案模$10^{9} + 7$. 因为第一次上课恰好有多少人,所以这个方案数是可以直接用组合数,暂

Codeforces 690 C3. Brain Network (hard) LCA

C3. Brain Network (hard) Breaking news from zombie neurology! It turns out that – contrary to previous beliefs – every zombie is born with a single brain, and only later it evolves into a complicated brain structure. In fact, whenever a zombie consum