Codeforces Round #423 Div. 2 F. Best Edge Weight (倍增法lca)(最小生成树mst)
2017-07-14 13:42
447 查看
ps:还是第一次做cf的f题,感觉算法不难,但是要想到做法,并结合算法还是要一定水平。很吃力的啃这道题,最后还是看着代码才搞懂,但至少还是跨出那一步了吧,加油。
题意:
给你n个点,m条边,接下来m行,每行三个数字,u,v,va。va是边值,u,v是连接边的两个点。
对于每条边单独考虑。问你在其他边边值不变的情况下,当前边的边值最大可以是多少,使得这条边必然在最小生成树内。
题解:
首先我们分两种情况考虑。
![](https://img-blog.csdn.net/20170714132806118?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGlfanVzdF9kb19pdA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
先建好一棵最小生成树,把边分成在mst内和不在mst内。
mst内:1-2,2-3,3-4,4-5
不在mst内:1-3,1-5
a. 当边u-v不在mst内的时候,它需要比点u-v内包含的在最小生成树内的边的最大值-1,这样它就可以代替那条最大的边。
在这张图就是1-3的最大值可以是va(2-3)-1 = 1,
b. 当边u-v在mst内的时候,它需要比所有包含它的不在mst内的边的最小的那条边值相等。
在这张图中,1-2在mst内,1-3和1-5都包含了1-2,而边值最小的是1-3,所以1-2的边值最大可以是3
对于情况a,我们就用倍增法求u-v之间的在mst内的最大边,预处理后的复杂度是logn。
对于情况b,我们首先对所有的不在mst内的边按边值大小进行排序,然后对于每一条边都更新它所包含的mst内的边的最大边值。
这里有个优化就是每条边都只需要更新一次,因为之前已经把不在mst内的边按边值排序排好了。
下面是代码———————————————
这里可以把倍增法的处理方法学习一下,以后求两点之间树边的最值,就可以用logn的复杂度求出来了。
代码:
题意:
给你n个点,m条边,接下来m行,每行三个数字,u,v,va。va是边值,u,v是连接边的两个点。
对于每条边单独考虑。问你在其他边边值不变的情况下,当前边的边值最大可以是多少,使得这条边必然在最小生成树内。
题解:
首先我们分两种情况考虑。
先建好一棵最小生成树,把边分成在mst内和不在mst内。
mst内:1-2,2-3,3-4,4-5
不在mst内:1-3,1-5
a. 当边u-v不在mst内的时候,它需要比点u-v内包含的在最小生成树内的边的最大值-1,这样它就可以代替那条最大的边。
在这张图就是1-3的最大值可以是va(2-3)-1 = 1,
b. 当边u-v在mst内的时候,它需要比所有包含它的不在mst内的边的最小的那条边值相等。
在这张图中,1-2在mst内,1-3和1-5都包含了1-2,而边值最小的是1-3,所以1-2的边值最大可以是3
对于情况a,我们就用倍增法求u-v之间的在mst内的最大边,预处理后的复杂度是logn。
对于情况b,我们首先对所有的不在mst内的边按边值大小进行排序,然后对于每一条边都更新它所包含的mst内的边的最大边值。
这里有个优化就是每条边都只需要更新一次,因为之前已经把不在mst内的边按边值排序排好了。
下面是代码———————————————
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <stack> #include <bitset> #include <queue> #include <set> #include <map> #include <string> #include <algorithm> using namespace std; #define clr(a,b) memset(a,b,sizeof(a)) #define pb(a) push_back(a) #define fir first #define se second #define LL long long typedef pair<int,int> pii; typedef pair<LL,int> pli; typedef pair<LL,LL> pll; const int inf = 0x3f3f3f3f; const int maxn = 2e5+5; const int ff = 11; LL mod = 1e9+7; double eps = 0.00000001; double PI = acos(-1); int n,m,fa[maxn],par[maxn][20],max_w[maxn][20],dep[maxn],in_mst[maxn],ans[maxn],r[maxn]; //par-边值,max_w-最大的边值,par-祖先,dep点的深度,in_mst-是否在mst内,r-表示这个点所在边的id struct edge { //定义边的结构体 int u,v,w,id; //w-边值,id-边的序号 } e[maxn]; vector<edge> G[maxn]; bool cmp(edge a,edge b) { return a.w < b.w; } int query(int x) { return fa[x] == x ? fa[x] : fa[x] = query(fa[x]); } void dfs(int u,int fa,int d) { dep[u] = dep[fa]+1; par[u][0] = fa; max_w[u][0] = d; for(int i = 1;i <= 18;i++) { par[u][i] = par[par[u][i-1]][i-1]; max_w[u][i] = max(max_w[u][i-1],max_w[par[u][i-1]][i-1]); } for(int i = 0;i < G[u].size();i++) { edge temp_e = G[u][i]; int v = temp_e.v; if(v == fa) continue; r[v] = temp_e.id; dfs(v, u, temp_e.w); } } int lca(int x,int y,int &d) //倍增求出lca { d = 0; if(dep[x] < dep[y]) swap(x, y); for(int i = 18;i >= 0;i--) { if(dep[par[x][i]] >= dep[y]) { d = max(d, max_w[x][i]); x = par[x][i]; } }// leap to the equal dep if(x == y) return x; for(int i=18;i>=0;i--) { if(par[x][i] != par[y][i]) { d = max(d, max(max_w[x][i], max_w[y][i])); x = par[x][i]; y = par[y][i]; } } // now they are both after lca 1 step d = max(d, max(max_w[x][0], max_w[y][0])); return par[x][0]; } void slove(int x,int u,int d) // u is lca { x = query(x); while(dep[x] > dep[u]) { ans[r[x]] = min(ans[r[x]], d); int y = query(par[x][0]); //这里用路径压缩,因为非mst内的边已经排好序了,所以每个mst内的边只要更新一次,就用路径压缩跳过 fa[x] = y; x = query(x); } } int main() { cin>>n>>m; for(int i = 1;i <= m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); e[i] = edge{u,v,w,i}; } sort(e+1,e+1+m,cmp); //按边值排序 clr(in_mst,0); for(int i = 1;i <= n;i++) fa[i] = i; for(int i = 1;i <= m;i++) { int x = e[i].u,y = e[i].v; int fx = query(x),fy = query(y); if(fx != fy) { fa[fy] = fx; in_mst[e[i].id] = 1; //表明这条边在mst内 G[x].pb(e[i]); //建mst edge tmp = e[i]; swap(e[i].u,e[i].v); G[y].pb(e[i]); } } dfs(1,0,0); //dfs预处理倍增的数组,还有两点之间最大的边值 clr(ans,inf); for(int i = 1;i <= n;i++) fa[i] = i; for(int i = 1;i <= m;i++) { if(!in_mst[e[i].id]) { //如果这条边没有在mst内 int x = e[i].u,y = e[i].v,u = lca(x,y,ans[e[i].id]); //求lca ans[e[i].id]--; //mst外的边就是点x~点y之间最大边值-1 slove(x,u,e[i].w-1); //mst内的边就用mst外的每一条边去更新,答案是最小的边值 slove(y,u,e[i].w-1); } } for(int i = 1;i <= m;i++) { if(ans[i] == inf) printf("-1 "); else printf("%d ",ans[i]); } cout<<endl; }
这里可以把倍增法的处理方法学习一下,以后求两点之间树边的最值,就可以用logn的复杂度求出来了。
代码:
void dfs(int u,int fa,int d) { //预处理 dep[u] = dep[fa]+1; par[u][0] = fa; max_w[u][0] = d; for(int i = 1;i <= 18;i++) { par[u][i] = par[par[u][i-1]][i-1]; max_w[u][i] = max(max_w[u][i-1],max_w[par[u][i-1]][i-1]); } for(int i = 0;i < G[u].size();i++) { edge temp_e = G[u][i]; int v = temp_e.v; if(v == fa) continue; r[v] = temp_e.id; dfs(v, u, temp_e.w); } } int lca(int x,int y,int &d) //倍增求出lca { d = 0; if(dep[x] < dep[y]) swap(x, y); for(int i = 18;i >= 0;i--) //先把两个点跳到同一高度 { if(dep[par[x][i]] >= dep[y]) { d = max(d, max_w[x][i]); x = par[x][i]; } }// leap to the equal dep if(x == y) return x; for(int i=18;i>=0;i--) //再一起跳 { if(par[x][i] != par[y][i]) { d = max(d, max(max_w[x][i], max_w[y][i])); x = par[x][i]; y = par[y][i]; } } // now they are both after lca 1 step d = max(d, max(max_w[x][0], max_w[y][0])); return par[x][0]; }
相关文章推荐
- codeforce 378 div 2 F —— Drivers Dissatisfaction (最小生成树,LCA,倍增)
- CodeForces 827D Round #423 Div2F&Div1D:LCA+路径压缩+MST(最小生成树)
- UVA 11354 Bond(最小生成树+lca+倍增求祖先节点)
- UVa 11354 - Bond(最小生成树+倍增lca)
- Minimum spanning tree for each edge CodeForces - 609E(ST算法+树链剖分(或倍增LCA)+最小生成树)
- HYSBZ - 3732 最小生成树+倍增Lca
- gym 101081 gym F. Auction of Services 最小生成树+倍增LCA
- 最小生成树和倍增法求lca(Uva11354Bond)
- 【bzoj4242】水壶 BFS+最小生成树+倍增LCA
- 【UVa】11354 Bond 最小生成树,动态LCA,倍增思想
- Codeforces Round #423 (Div. 1, rated, based on VK Cup Finals) D. Best Edge Weight(最小生成树+LCA+树链剖分)
- UVA 11354 Bond(最小生成树+LCA倍增)
- BZOJ 3732 Network —— 最小生成树 + 倍增LCA
- codeforces 733 F. Drivers Dissatisfaction(最小生成树+lca+倍增去环)
- 【BJOI2010】次小生成树-最小生成树+倍增LCA
- CodeForces 609E Minimum spanning tree for each edge (lca+最小生成树+倍增)
- 2015 年 蓝桥杯 A 组 C/C++ 第十题 灾后重建 【最小生成树 + LCA倍增 + 线段树维护区间max】
- bzoj3732(同货车运输,倍增lca+最小生成树)
- 【BZOJ2238】Mst 最小生成树+LCA+堆
- NOIP2013 货车运输 [LCA] [RMQ] [最小生成树] [ST倍增]