zoukankan      html  css  js  c++  java
  • 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)]$最优状态里,需要去掉它个贡献

      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 }
  • 相关阅读:
    shell 命令
    unzip解压失败 添加tar 解压
    tomcat
    Linux常用命令
    压缩归档与解压
    Linux的任务计划管理
    A01. openstack架构实战-openstack基本环境准备
    ubuntu16.04 server版破解密码
    Ubuntu Server 18.04 网络设置不生效的解决
    带宽单位 Mbps 及换算方式
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9898493.html
Copyright © 2011-2022 走看看