CF 1000G Two-Paths (树形DP)

Posted guapisolo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
",solve(x,y));
119     return 0;
120 }

 

以上是关于CF 1000G Two-Paths (树形DP)的主要内容,如果未能解决你的问题,请参考以下文章

CF1000G Two-Paths

CF839 C 树形DP 期望

cf842C 树形dp+gcd函数

CF767C Garland--树形dp

树形dp——cf1029E

[CF486D] Valid Sets - 树形dp