CF1000G Two-Paths
题目大意:给你一棵树,其中点上和边上都有值。定义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的更多相关文章
- [LeetCode] Binary Tree Paths 二叉树路径
Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...
- [LeetCode] Unique Paths II 不同的路径之二
Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...
- [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 ...
- leetcode : Binary Tree Paths
Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree: 1 ...
- UVA 10564 Paths through the Hourglass[DP 打印]
UVA - 10564 Paths through the Hourglass 题意: 要求从第一层走到最下面一层,只能往左下或右下走 问有多少条路径之和刚好等于S? 如果有的话,输出字典序最小的路径 ...
- 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 ...
- Leetcode Unique Paths II
Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...
- POJ 3177 Redundant Paths(边双连通的构造)
Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 13717 Accepted: 5824 ...
- soj 1015 Jill's Tour Paths 解题报告
题目描述: 1015. Jill's Tour Paths Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description Every ...
- Unique Paths II
这题在Unique Paths的基础上增加了一些obstacle的位置,应该说增加的难度不大,但是写的时候对细节的要求多了很多,比如,第一列的初始化会受到之前行的第一列的结果的制约.另外对第一行的初始 ...
随机推荐
- redis过期键删除策略以及大key删除方法
今天遇到了一个前同事挖的坑,刷新缓存中商品信息时先让key过期,然后从数据库里取最新数据然后再放到缓存中,他是这样写的 redisTemplate.expire(CacheConst.GOOGS_PR ...
- Wait示例分析
wait方法使"当前线程"进入阻塞(等待)状态. 示例分析: public class TestWait { public static void main(String[] ar ...
- 本地通信实例(AF_UNIX) (转载)
转自:http://www.groad.net/bbs/thread-1709-1-1.html 程序说明: 程序里包含服务端和客户端两个程序,它们之间使用 AF_UNIX 实现本机数据流通信.使用 ...
- bzoj 1306: [CQOI2009]match循环赛【dfs+剪枝】
大力剪枝,最后洛谷上还开了o2才过-- 大概这样剪枝: 1.搜索中,一个队当前得分超过要求或者一个队剩下的比赛场数全赢也达不到要求则return: 2.注意到如果平局,最总分的贡献是2,否则是3,所以 ...
- bzoj 3714: [PA2014]Kuglarz【最小生成树】
参考:https://blog.csdn.net/aarongzk/article/details/48883741 没想到吧.jpg 来自题解: "如果用sum[i]表示前i个杯子底球的总 ...
- P4170 [CQOI2007]涂色
传送门 区间dp,设\(f[l][r]\)表示区间\((l,r)\)的最小次数,当\(l==r\)时为\(1\),当\(s[l]==s[r]\)时为\(min(f[l][r-1],f[l+1][r]) ...
- 洛谷P3833 [SHOI2012]魔法树(树链剖分)
传送门 树剖板子…… 一个路径加和,线段树上打标记.一个子树询问,dfs的时候记录一下子树的区间就行 // luogu-judger-enable-o2 //minamoto #include< ...
- Element-wise operations
Element-wise operations An element-wise operation operates on corresponding elements between tensors ...
- infuxdb时序数据库的下载(windows)一
因为众所周知的原因,点击上图的 “v1.7.6” 发现根本不起作用,其实真正的下载链接就在页面中. 把链接复制下来,拷贝到浏览器中即可下载. 这里面是最新版,如果要下载旧版本的,将链接中的1.7.6替 ...
- ROS学习笔记九:ROS工具
ROS有各种工具可以帮助用户使用ROS.应该指出,这些GUI工具是对输入型命令工具的补充.如果包括ROS用户个人发布的工具,那么ROS工具的数量很庞大.其中,本文讨论的工具是对于ROS编程非常有用的辅 ...