2 条题解
-
0
把路径拆一下,最后的收益变成 加上在图中选一个中间点能获得的最大收益。前面的不难计算,树上差分加 LCA 即可。那么题目转化为:给出一条树上路径,在树上找到一个点使得它的权值减去到路径的最短距离的两倍最大。
对于一个节点 ,如果它经过一条边到另一个节点 演讲完再回来的收益比在这个节点直接演讲的收益还要大,即 ,那么可以将 直接修改为 。
如果用合适的顺序把所有 更新成经过 的最大的收益,那么就只需要求出 到 的路径上 的最大值就可以了。
这个更新可以简单用 dfs 实现。具体的,在 dfs 中按顺序更新每一对相邻的节点的 值,第一遍 dfs 即可把每个节点的 值用子树中所有节点的 值更新,第二遍 dfs 即可把每个节点的祖先节点更新的 值推到它的子树上所有节点上。这样,整棵树的 值就都被成功更新了。
最后可以用倍增求出树上两点路径上的最大 值。
赛时因为直接把 更新 的部分分代码复制过来导致没发现最后求路径上最大 值还需要用倍增实现导致 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
#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
- 上传者