CF1000G Two-Paths (树形DP)
题目大意:给你一棵树,点有点权$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)的更多相关文章
- 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 ...
- SPOJ6717 Two Paths 树形dp
首先有朴素的\(O(n^2)\)想法 首先枚举断边,之后对于断边之后的两棵子树求出直径 考虑优化这个朴素的想法 考虑换根\(dp\) 具体而言,首先求出\(f[i], fs[i]\)表示\(i\)号点 ...
- 牛客第八场 C-counting paths 树形dp计数
题目地址 题意 给你一颗树 初始点颜色全部为白色 对于每一个满足要求一的点集s f(s)的定义为先把点集内的点染黑 满足要求二的路径集合数量 要求一为两两黑点之间不能出现白色的点 要求二为将这个路径集 ...
- 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 ...
- HDU4003Find Metal Mineral[树形DP 分组背包]
Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Other ...
- 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 ...
- hdu 4003 Find Metal Mineral 树形DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal miner ...
- poj3162(树形dp+优先队列)
Walking Race Time Limit: 10000MS Memory Limit: 131072K Total Submissions: 5409 Accepted: 1371 Ca ...
- POJ 3162.Walking Race 树形dp 树的直径
Walking Race Time Limit: 10000MS Memory Limit: 131072K Total Submissions: 4123 Accepted: 1029 Ca ...
随机推荐
- 01 C#基础
第一天 .net平台(中国移动互联网平台): .net框架(信号塔): CLR(公共语言运行时) .Net类 库 我们使用的语言是——C# 2.解决方案项目与类的关系: 解决方案:公司 项目:部门 类 ...
- [USACO17JAN] Subsequence Reversal序列反转 (dfs+记忆化)
题目大意:给你一个序列,你可以翻转任意一段子序列一次,求最长不下降子序列长度 tips:子序列可以不连续,但不能破坏在原序列中的顺序 观察数据范围,n<=50,很小,考虑dfs *dfs来跑区间 ...
- XPATH怎么获取TITLE中有中文的标签
定位 //*[@id="kkpager"]/div[1]/span[1]/a[@title="下一页"] 获取元素 txt4 = txt.xpath('//*[ ...
- django-4-模板标签,模板继承
<<<模板标签>>> {% for %}{% endfor %} 循环 {% if %}{% elif %}{% else %}{% endif %} 判断 {% ...
- Redis - Python操作Redis
目录 Python操作Redis 一. Redis安装和基本使用 二. Python操作Redis API使用 1.操作模式 2.连接池 3.Django配置Redis 4.操作 Python操作Re ...
- bitset优化背包
题目:https://agc020.contest.atcoder.jp/tasks/agc020_c 回忆下一题,是零一背包,主要的做法就是凑出最接近sum/2的价值,然后发现现在的背包的容量是20 ...
- C#-委托 lambda 匿名方法 匿名类型
1.lambda 匿名方法 匿名类型 delegate void d1(); d1 d = delegate(){Console.WriteLine("this is a test" ...
- java string遇到的一个奇葩bug
String abc = "1"; HashMap<String, String> hMap = new HashMap<String, String>() ...
- POJ 3071
求概率.其实跟枚举差不多,输入n即是要进行n轮比赛.对每一支球队,设求1的概率,首先1要与2比赛为p1,这是第一轮,第二轮时,1要与3(打败3为p2),4(打败4为p3)中胜者比赛,由于是概率,则两者 ...
- 怎样利用JDBC连接并操作Oracle数据库
之前学习.NET的时候.以前利用ODBC进行连接数据库,而在Java中通常採用JDBC连接数据库,这里以oracle数据库为例简单的总结一下利用JDBC怎样连接并操作数据库. 1.连接 public ...