1. 程式人生 > >CF 1000G Two-Paths (樹形DP)

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 }