CF E2 - Daleks' Invasion (medium) (LCA求两点树上路径上的最大边权)
Posted shuaihui520
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF E2 - Daleks' Invasion (medium) (LCA求两点树上路径上的最大边权)相关的知识,希望对你有一定的参考价值。
http://codeforces.com/contest/1184/problem/E2
题意:给出一副图,首先求出这幅图的最小生成树 , 然后修改这幅图上不属于最小生成树的边权,使得修改后的图在求一边生成树的时候可以包含被修改的边(注意:修改的边权要最大 )题目规定只有一课生成树
分析:
现在我们需要解决所有非树边的任务(MST保证是惟一的)。我们要求对于非树边(u, v),正确答案是u和v之间路径上的最大权值MST。(证明:≤:由MSTs的循环特性可知;≥:如果(u, v)的重量大于这个最大值,然后用(u, v)交换获得最大值的边,会得到一个更便宜的树a矛盾。
所以现在我们的任务就是求任意两点在生成树上的路径最大边权。这题我们可以用LCA的思想去完成,我们现在预处理出了一条路上走过的最大值,那么答案所求mx=max(mx(u->w) , mx(v->w)) ;w为u,v的最近公共祖先,这里采用倍增法的思想去完成
#include<bits/stdc++.h> using namespace std ; int n,m; const int maxn = 1e6+3; vector<pair<int,int> >G[maxn]; int pre[maxn],fa[maxn][19],dep[maxn],mx[maxn][19],ans[maxn]; struct no int id,u,v,w; a[maxn]; bool cmp(no a , no b) return a.w<b.w; int ffind(int x) if(pre[x]==x) return x; pre[x]=ffind(pre[x]); return pre[x]; void dfs(int u , int p) for(int i=0 ; i<G[u].size() ; i++) int v=G[u][i].first; if(p==v) continue; dep[v]=dep[u]+1; fa[v][0]=u; mx[v][0]=G[u][i].second; dfs(v,u); int lca(int u , int v) if(dep[u]>dep[v]) swap(u,v); for(int i=0 ; i<18 ; i++) if((dep[v]-dep[u])&(1<<i)) v=fa[v][i]; if(u==v) return u; for(int i=17 ; i>=0 ; i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return fa[u][0]; int ask(int u , int st) int ret=0; for(int i=0 ; i<18 ; i++) if(st&(1<<i)) ret=max(ret,mx[u][i]),u=fa[u][i]; return ret; int main() scanf("%d%d",&n,&m); for(int i=0 ; i<m ; i++) a[i].id=i; scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); ///卡鲁思 for(int i=1 ; i<=n ; i++) pre[i]=i; sort(a,a+m,cmp); for(int i=0 ; i<m ; i++) int u=ffind(a[i].u) , v=ffind(a[i].v); if(u!=v) pre[u]=v; ans[a[i].id]=-1; G[a[i].u].push_back(a[i].v,a[i].w); G[a[i].v].push_back(a[i].u,a[i].w); ///lca dep[1]=1; dfs(1,0); for(int i=1 ; i<18 ; i++) for(int j=1 ; j<=n ; j++) fa[j][i]=fa[fa[j][i-1]][i-1]; mx[j][i]=max(mx[j][i-1],mx[fa[j][i-1]][i-1]); for(int i=0 ; i<m ; i++) if(ans[a[i].id]!=-1) int u=a[i].u ,v=a[i].v , w=lca(u,v); ans[a[i].id]=max(ask(u,dep[u]-dep[w]),ask(v,dep[v]-dep[w])); for(int i=0 ; i<m ; i++) if(ans[i]!=-1) printf("%d ",ans[i]);
以上是关于CF E2 - Daleks' Invasion (medium) (LCA求两点树上路径上的最大边权)的主要内容,如果未能解决你的问题,请参考以下文章
cf1216E2 Numerical Sequence (hard version) 二分查找思维题