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的位置,应该说增加的难度不大,但是写的时候对细节的要求多了很多,比如,第一列的初始化会受到之前行的第一列的结果的制约.另外对第一行的初始 ...
随机推荐
- sql server 日期模糊查询
转换成varchar类型 ) like '%2010-10-09%' 两个字段拼接成一个字段 SELECT C0252_ID, C0252_name,C0252_Addr, ((select top ...
- bzoj3550: [ONTAK2010]Vacation(单纯形法+线性规划)
传送门 直接暴力把线性规划矩阵给打出来然后单纯形求解就行了 简单来说就是每个数记一个\(d_i\)表示选或不选,那么就是最大化\(\sum d_ic_i\),并满足一堆限制条件 然后不要忘记限制每个数 ...
- C# DateTime.Now 详解
//2008年4月24日 System.DateTime.Now.ToString("D"); //2008-4-24 System.DateTime.Now.ToString(& ...
- NOIp 2017 奶酪 【并查集】 By cellur925
题目传送门 Orz去年考场上做这道题的我应该还在抱怨没学过空间几何,不一会太困了就开始打瞌睡,然后为了防止睡觉开始在devc++上写默写离骚(逃 思路:如果两个空洞相交,那么把他们并在一个集合里.最后 ...
- php安装的扩展php -m可以看到,但是phpinfo()看不到,php-fpm关闭了重新打开还是不行?
问答 问答详情 php安装的扩展php -m可以看到,但是phpinfo()看不到,php-fpm关闭了重新打开还是不行? centos apache linux html php 3.2k 次浏 ...
- InputFilter在过滤空格时重复输入的问题
正确做法:editText.setFilters(new InputFilter[] { new InputFilter() { @Override public CharSequence filte ...
- Looper、MessageQueue、Message、Handler的关系
1.快速复习 1.1 基本装置 类 装置名 作用 线程中数量 Looper 消息分发装置 从消息队列中取出一个消息,交给对应的Handler处理消息. 1 MessageQueue 消息队列 保存所有 ...
- easy ui diglog 点击关闭,触发事件
$('#dialogDiv').dialog({ onClose:function(){ alert('11111111') ; }});
- WPF学习09:数据绑定之 Binding to List Data
从WPF学习03:Element Binding我们可以实现控件属性与控件属性的绑定. 从WPF学习07:MVVM 预备知识之数据绑定 我们可以实现控件属性与自定义对象属性的绑定. 而以上两个功能在实 ...
- String的用法——获取功能
package cn.itcast_04; /* String类获取功能 int length():获取字符的长度 char charAt(int index):获取指定索引位置的字符 int ind ...