2 条题解

  • 0
    @ 2026-5-7 10:12:02

    把路径拆一下,最后的收益变成 cx+cydisx,yc_x+c_y-dis_{x,y} 加上在图中选一个中间点能获得的最大收益。前面的不难计算,树上差分加 LCA 即可。那么题目转化为:给出一条树上路径,在树上找到一个点使得它的权值减去到路径的最短距离的两倍最大。

    对于一个节点 xx,如果它经过一条边到另一个节点 yy 演讲完再回来的收益比在这个节点直接演讲的收益还要大,即 cx<cy2×wx,yc_x<c_y-2\times w_{x,y},那么可以将 cxc_x 直接修改为 cy2×wx,yc_y-2\times w_{x,y}

    如果用合适的顺序把所有 cic_i 更新成经过 ii 的最大的收益,那么就只需要求出 xxyy 的路径上 cic_i 的最大值就可以了。

    这个更新可以简单用 dfs 实现。具体的,在 dfs 中按顺序更新每一对相邻的节点的 cc 值,第一遍 dfs 即可把每个节点的 cc 值用子树中所有节点的 cc 值更新,第二遍 dfs 即可把每个节点的祖先节点更新的 cc 值推到它的子树上所有节点上。这样,整棵树的 cc 值就都被成功更新了。

    最后可以用倍增求出树上两点路径上的最大 cc 值。

    赛时因为直接把 O(n2logn)O(n^2\log n) 更新 cc 的部分分代码复制过来导致没发现最后求路径上最大 cc 值还需要用倍增实现导致 TLE,下面是赛时代码修改后可以 AC 的代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=2e5+5;
    using pii=pair<int,int>;
    #define fi first
    #define se second
    int c[N],oc[N];
    vector<pii>g[N];
    int s[N];//到 1 的距离
    int dep[N];
    int fa[N][20];
    int mxc[N][20];
    void dfs(int x,int l){
    	dep[x]=dep[l]+1;
    	fa[x][0]=l;
    	for(int i=1;i<=19;i++){
    		fa[x][i]=fa[fa[x][i-1]][i-1];
    	}
    	for(pii t:g[x]){
    		int y=t.fi,w=t.se;
    		if(y==l)continue;
    		s[y]=s[x]+w;
    		dfs(y,x);
    	}
    }
    int lca(int x,int y){
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=19;i>=0;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
    	if(x==y)return x;
    	for(int i=19;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
    	return fa[x][0];
    }
    int dis(int x,int y){
    	int t=lca(x,y);
    	return s[x]+s[y]-s[t]-s[t];
    }
    void dfsa(int x,int l){
    	for(pii pp:g[x]){
    		int y=pp.fi,w=pp.se;
    		if(y==l)continue;
    		c[y]=max(c[y],c[x]-w-w);
    		dfsa(y,x);
    		c[x]=max(c[x],c[y]-w-w);
    	}
    }
    void dfs1(int x,int l){
    	mxc[x][0]=c[x];
    	for(int i=1;i<=19;i++){
    		mxc[x][i]=max(mxc[x][i-1],mxc[fa[x][i-1]][i-1]);
    	}
    	for(pii pp:g[x]){
    		int y=pp.fi;
    		if(y==l)continue;
    		dfs1(y,x);
    	}
    }
    int sol(int x,int y){
    	int ans=0;
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=19;i>=0;i--)if(dep[fa[x][i]]>=dep[y])ans=max(ans,mxc[x][i]),x=fa[x][i];
    	if(x==y)return max(ans,c[x]);
    	for(int i=19;i>=0;i--)if(fa[x][i]!=fa[y][i])ans=max({ans,mxc[x][i],mxc[y][i]}),x=fa[x][i],y=fa[y][i];
    	//注意要先更新再跳!
    	return max({ans,mxc[x][1],mxc[y][1]});
    }
    signed main(){
    	ios::sync_with_stdio(0);cin.tie(0);
    	int n,q;cin>>n>>q;
    	for(int i=1;i<=n;i++){
    		cin>>c[i];oc[i]=c[i];
    	}
    	for(int i=1;i<n;i++){
    		int u,v,w;cin>>u>>v>>w;
    		g[u].emplace_back(v,w);
    		g[v].emplace_back(u,w);
    	}
    	dfs(1,0);//初始化倍增 LCA 数组
    	dfsa(1,0);dfsa(1,0);//更新 c
    	dfs1(1,0);//初始化倍增求 c 最大值数组
    	while(q--){
    		int x,y;cin>>x>>y;
    		int ans=oc[x]+oc[y]-dis(x,y);
    		cout<<ans+sol(x,y)<<"\n";
    	}
    	return 0;
    }
    
    • 0
      @ 2025-10-8 17:00:40
      #include<bits/stdc++.h>
      using namespace std;
      const int N=2e5+10;
      typedef long long LL;
      LL c[N], f[N][25], d[N], sum, mx[N][25], cc[N];
      struct node{int y; LL w;};
      vector<node> G[N]; int D, dep[N];
      void dfs1(int x, int fa){
          for(node i: G[x]) if(i.y!=fa){
              d[i.y]=d[x]+i.w;
              c[i.y]=max(c[i.y], c[x]-2*i.w);
              dfs1(i.y, x);
              c[x]=max(c[x], c[i.y]-2*i.w);
          }
      }
      void dfs2(int x, int fa){
          f[x][0]=fa; dep[x]=dep[fa]+1; mx[x][0]=c[x];
          for(int i=1; i<=D; i++){
              f[x][i]=f[f[x][i-1]][i-1];
              mx[x][i]=max(mx[x][i-1], mx[f[x][i-1]][i-1]);
          }
          for(node i: G[x]) if(i.y!=fa) dfs2(i.y, x);
      }
      int LCA(int x, int y){
          if(dep[x]<dep[y]) swap(x, y);
          for(int i=D; i>=0; i--) if(dep[f[x][i]]>=dep[y]){
              sum=max(sum, mx[x][i]);
              x=f[x][i];
          }
          if(x==y){
              sum=max(sum, mx[x][0]);
              return x;
          }
          for(int i=D; i>=0; i--) if(f[x][i]!=f[y][i]){
              sum=max({sum, mx[x][i], mx[y][i]});
              x=f[x][i], y=f[y][i];
          }
          sum=max({sum, mx[x][1], mx[y][1]});
          return f[x][0];
      }
      int main(){
          int n, m; scanf("%d%d", &n, &m); D=log2(n);
          for(int i=1; i<=n; i++) scanf("%lld", &c[i]), cc[i]=c[i];
          for(int i=1; i<n; i++){
              int x, y; LL w; scanf("%d%d%lld", &x, &y, &w);
              G[x].push_back({y, w}); 
              G[y].push_back({x, w});
          }
          d[0]=0; dfs1(1, 0);  dfs1(1, 0); 
          dep[0]=0; dfs2(1, 0);
          for(int i=1; i<=m; i++){
              int x, y; scanf("%d%d", &x, &y);
              sum=0; int lca=LCA(x, y);
              LL t=d[x]+d[y]-2*d[lca];
              printf("%lld\n", cc[x]+cc[y]+sum-t);
          }
          return 0;
      }
      
      • 1

      信息

      ID
      2284
      时间
      2000ms
      内存
      512MiB
      难度
      9
      标签
      递交数
      8
      已通过
      6
      上传者