CF 1000G 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$的儿子,来去掉它个贡献

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define N 301000
  5 #define uint unsigned int
  6 #define ll long long
  7 #define mod 1000000007
  8 using namespace std;
  9
 10 int gint()
 11 {
 12     int ret=0,f=1;char c=getchar();
 13     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
 14     while(c>=‘0‘&&c<=‘9‘){ret=ret*10+c-‘0‘;c=getchar();}
 15     return ret*f;
 16 }
 17 int n,q,cte;
 18 int a[N],fe[N],fa[N],head[N];
 19 ll f[N][3],g[N][2],vsum[N],esum[N];
 20 struct Edge{int to,nxt,val;}edge[N*2];
 21 void ae(int u,int v,int w){
 22     cte++;edge[cte].to=v,edge[cte].val=w;
 23     edge[cte].nxt=head[u],head[u]=cte;
 24 }
 25 int use[N],dep[N];
 26 ll dis[N],sum[N];
 27 int ff[N][20];
 28 void dfs1(int u,int dad)
 29 {
 30     ff[u][0]=u;
 31     for(int j=head[u];j;j=edge[j].nxt){
 32         int v=edge[j].to;
 33         if(v==dad) continue;
 34         dep[v]=dep[u]+1,fa[v]=u,ff[v][1]=u,fe[v]=edge[j].val;
 35         dis[v]=dis[u]+edge[j].val;
 36         vsum[v]=vsum[u]+a[v];
 37         esum[v]=esum[u]+edge[j].val;
 38         dfs1(v,u);
 39         if(f[v][0]+a[v]-2ll*edge[j].val>0)
 40             use[v]=1,f[u][0]+=f[v][0]+a[v]-2ll*edge[j].val;
 41     }
 42 }
 43 void dfs2(int u)
 44 {
 45     for(int j=head[u];j;j=edge[j].nxt){
 46         int v=edge[j].to;
 47         if(v==fa[u]) continue;
 48         if(use[v]){
 49             f[v][1]=f[u][0]-(f[v][0]+a[v]-2ll*edge[j].val);
 50             f[v][2]=max(0ll,f[u][2]+f[v][1]+a[u]-2ll*edge[j].val);
 51         }else{
 52             f[v][1]=f[u][0];
 53             f[v][2]=max(0ll,f[u][2]+f[v][1]+a[u]-2ll*edge[j].val);
 54         }
 55         g[v][0]=g[u][0]+f[v][0];
 56         g[v][1]=g[u][1]+f[v][1];
 57         dfs2(v);
 58     }
 59 }
 60 void get_lca()
 61 {
 62     for(int j=2;j<=19;j++)
 63         for(int i=1;i<=n;i++)
 64             ff[i][j]=ff[ ff[i][j-1] ][j-1];
 65 }
 66 int Lca(int x,int y,int &fx,int &fy)
 67 {
 68     int px=x,py=y,ans,dx,dy,flag=1;
 69     if(dep[x]<dep[y]) swap(x,y);
 70     for(int i=19;i>=0;i--)
 71         if(dep[ff[x][i]]>=dep[y]) x=ff[x][i];
 72     for(int i=19;i>=0;i--)
 73         if(ff[x][i]!=ff[y][i]) x=ff[x][i],y=ff[y][i];
 74         else ans=ff[x][i];
 75     x=px,y=py;
 76     dx=dep[ans]+1;
 77     dy=dep[ans]+1;
 78     for(int i=19;i>=0;i--){
 79         if(dep[ff[x][i]]>=dx) x=ff[x][i];
 80         if(dep[ff[y][i]]>=dy) y=ff[y][i];
 81     }fx=x,fy=y;
 82     return ans;
 83 }
 84 ll solve(int x,int y)
 85 {
 86     if(x==y) return f[x][0]+f[x][2]+a[x];
 87     else if(fa[x]==y) return f[x][0]+f[x][1]+f[y][2]+a[x]+a[y]-fe[x];
 88     else if(fa[y]==x) return f[y][0]+f[y][1]+f[x][2]+a[x]+a[y]-fe[y];
 89     int fx,fy,lca;
 90     lca=Lca(x,y,fx,fy);
 91     ll ans=0;
 92     ans+=(vsum[x]+vsum[y]-vsum[lca]-vsum[fa[lca]])-(esum[x]+esum[y]-2ll*esum[lca]);
 93     ans+=f[x][0]+f[y][0];
 94     if(y==fy&&x!=fx){
 95         ans+=g[x][1]+g[y][1]-2ll*g[lca][1]-f[fx][1];
 96         if(use[fx]) ans-=f[fx][0]+a[fx]-2ll*fe[fx];
 97     }else{
 98         ans+=g[x][1]+g[y][1]-2ll*g[lca][1]-f[fy][1];
 99         if(use[fy]) ans-=f[fy][0]+a[fy]-2ll*fe[fy];
100     }
101     ans+=f[lca][2];
102     return ans;
103 }
104
105 int main()
106 {
107     scanf("%d%d",&n,&q);
108     int x,y,w;
109     for(int i=1;i<=n;i++)
110         a[i]=gint();
111     for(int i=1;i<n;i++)
112         x=gint(),y=gint(),w=gint(),ae(x,y,w),ae(y,x,w);
113     dep[1]=1;
114     vsum[1]=a[1],dfs1(1,-1);
115     g[1][0]=f[1][0],dfs2(1);
116     get_lca();
117     for(int i=1;i<=q;i++)
118         x=gint(),y=gint(),printf("%lld\n",solve(x,y));
119     return 0;
120 }

原文地址:https://www.cnblogs.com/guapisolo/p/9898493.html

时间: 2024-07-31 14:10:13

CF 1000G Two-Paths (树形DP)的相关文章

CF 486D vailid set 树形DP

As you know, an undirected connected graph with n nodes and n - 1 edges is called a tree. You are given an integer d and a tree consisting of n nodes. Each node i has a value ai associated with it. We call a set S of tree nodes valid if following con

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 settlements numbered from 1 to n. Moving through the swamp is very difficult, so people tramped exactly n - 1 paths. Each of these paths connects some p

CF EDU 1101D GCD Counting 树形DP + 质因子分解

CF EDU 1101D GCD Counting 题意 有一颗树,每个节点有一个值,问树上最长链的长度,要求链上的每个节点的GCD值大于1. 思路 由于每个数的质因子很少,题目的数据200000<2*3*5*7*11*13*17=510510.所以每个节点的质因子个数不多.那么树形DP的时候直接枚举每种因子即可. //#pragma GCC optimize(3) //#pragma comment(linker, "/STACK:102400000,102400000") /

CF 219D Choosing Capital for Treeland 树形DP 好题

一个国家,有n座城市,编号为1~n,有n-1条有向边 如果不考虑边的有向性,这n个城市刚好构成一棵树 现在国王要在这n个城市中选择一个作为首都 要求:从首都可以到达这个国家的任何一个城市(边是有向的) 所以一个城市作为首都,可能会有若干边需要改变方向 现在问,选择哪些城市作为首都,需要改变方向的边最少. 输出最少需要改变方向的边数 输出可以作为首都的编号 树形DP 先假定城市1作为首都 令tree(i)表示以i为根的子树 dp[i]表示在tree(i)中,若以i为首都的话,需要改变的边数 第一次

CF 461B Appleman and Tree 树形DP

Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices are colored white. Consider a set consisting of k (0 ≤ k < n) edges of Appleman's tree. If Appleman deletes these edges from the tree, then

hdu4003 树形dp+分组背包

http://acm.hdu.edu.cn/showproblem.php?pid=4003 Problem Description Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on

hdu 4003 Find Metal Mineral 树形DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on Mars to collect

HDOJ 5293 Tree chain problem LCA+树链剖分+树形DP

[题意] 给定一颗树上的几条链和每条链的权值,求能取出的不含有公共节点的链的最大权值.... [解] 预处理每条链的lca 树形DP, d[i]表示取到这个节点时可以得到的最大值 , sum[i]=sigma( d[k] | k 是i的子节点) 如果不取i  d[i]=sum[i] 如果取i , e是lca为i的链则 d[i]=max(d[i],e的权值+sigma(sum[k])-sigma(d[k]))  k为树链上的点 可以用树链剖分+树装数组在nlogn的时间复杂度内求链上的值 Tree

【转】【DP_树形DP专辑】【9月9最新更新】【from zeroclock&#39;s blog】

树,一种十分优美的数据结构,因为它本身就具有的递归性,所以它和子树见能相互传递很多信息,还因为它作为被限制的图在上面可进行的操作更多,所以各种用于不同地方的树都出现了,二叉树.三叉树.静态搜索树.AVL树,线段树.SPLAY树,后缀树等等.. 枚举那么多种数据结构只是想说树方面的内容相当多,本专辑只针对在树上的动态规划,即树形DP.做树形DP一般步骤是先将树转换为有根树,然后在树上进行深搜操作,从子节点或子树中返回信息层层往上更新至根节点.这里面的关键就是返回的信息部分,这个也没一般性的东西可讲