题意:

  n个城市,m条路,每条路有个危险值,要使得从s走到t的危险值最小。回答q个询问,每个询问有s和t,要求输出从s到t最小的危险值。(5万个点,10万条边)

思路:

  其实要求的是任意点对之间的最小瓶颈路的权值。

  先对图求一次MST,那么所有的瓶颈路都在上面。但是q<=5万,即使预先求出所有点对,也需要O(n*n),太大了。如果对于每个询问才来找答案,这又更慢了。所以得优化。

  优化方案(1):先求出生成树,对于每次询问的两个点,求一次LCA,两个点到LCA所经过的边其中一条边就是答案。很不幸,如果树很稀疏,树枝又很长,那么每次求LCA相当于O(n)的复杂度。

  优化方案(2):鉴于方案(1),要解决的是树枝很长的情况,由于要求的是区间最值,那么类似于RMQ问题了,只是在树上而不是序列中而已。假如将某个点p到其LCA之间的一条链作为一个区间的话,那么这段区间的最值,就是p到(p+LCA)/2与(p+LCA)/2到LCA两个区间的最值再取最值。这又变成了类似于ST算法了。

  

  具体做法可以这样:

  (1)预处理每个节点p到p+1,p+2...直到树根的这段区间的最值,那么得到m[p,p+1],m[p,p+2],m[p,p+4]...。大小是以2的幂为单位的。若某个点到树根的距离并不是刚好为2的整数次幂,那么这段放弃掉,因为总有点到树根的距离是恰好满足的,那么必要时,找这个区间即可。

  (2)在查询时,两节点分别到他们的LCA所经过的边不断更新答案。

  倍增算法:此代码用于优化求LCA的速度,以及从p到LCA这段区间的最值。保证在任何树的情况下都是O(logn)。

 void preprocess(int n)//预处理2的幂次大小的区间内的最值
{
for(int i=; i<=n; i++) //初始化,及先记录到父亲的距离
{
anc[i][]=far[i];
maxcost[i][]=cost[i][far[i]];
for(int j=; (<<j)<n; j++)
anc[i][j]=-;
}
for(int j=; (<<j)<n; j++)
{
for(int i=; i<=n; i++ )
{
int e=anc[i][j-];
if(e>)
{
anc[i][j]=anc[e][j-]; //将2的j次幂,分成两个2的j-1次来组成。
maxcost[i][j]=max(maxcost[i][j-],maxcost[e][j-]);
}
}
}
} int query(int p,int q) //先找LCA,再求答案
{
int tmp, log, i;
if(level[p]<level[q]) swap(p,q);//保持p更深一些 for(log=; (<<log)<=level[p]; log++);//统计最深要几层
--log;
int ans=-;
for(int i=log; i>=; i--)//将p提到与q同层
{
if(level[p]-(<<i)>=level[q])//这一步关键,只要多于level[q]的部分都会被抹去
{
ans=max(ans, maxcost[p][i]);
p=anc[p][i];
}
} if(p==q) return ans;//LCA为q for(int i=log; i>=; i--)//同时往LCA方向更新,直到成为LCA的孩子
{
if(anc[p][i]> && anc[p][i]!=anc[q][i] )
{
ans=max(ans, maxcost[p][i]);
p=anc[p][i];
ans=max(ans, maxcost[q][i]);
q=anc[q][i];
}
}
ans=max(ans, cost[p][far[p]]);//还有一层,别忘了
ans=max(ans, cost[q][far[q]]); return ans;
}

主要优化代码注释

  

 #include <bits/stdc++.h>
#define INF 0x7f7f7f7f
#define pii pair<int,int>
#define LL long long
using namespace std;
const int N=;
int a[N], b[N], w[N], seq[N]; //求MST用的
int pre[N], level[N], far[N], maxcost[N][], anc[N][];
int vis[N];
vector<int> vect[N]; //建树时用
map<int,int> cost[N]; int cmp(int a,int b){return w[a]<w[b];}
int find(int x){return pre[x]==x? x: pre[x]=find(pre[x]);} //并查集 void DFS(int x,int flo)
{
vis[x]=;
level[x]=flo; //记录在哪一层
for(int i=; i<vect[x].size(); i++)
{
int t=vect[x][i];
if(!vis[t])
{
far[t]=x; //用孩子索引父亲
DFS(t, flo+);
}
}
} void preprocess(int n)
{
for(int i=; i<=n; i++) //对于每个点
{
anc[i][]=far[i];
maxcost[i][]=cost[i][far[i]]; //与父亲的距离。
for(int j=; (<<j)<n; j++) //初始化祖先为-1
anc[i][j]=-;
}
for(int j=; (<<j)<n; j++) //仅需到n-1即可。
{
for(int i=; i<=n; i++ )
{
int e=anc[i][j-];
if(e>)
{
anc[i][j]=anc[e][j-]; //将2的j次幂,分成两个2的j-1次来组成。
maxcost[i][j]=max(maxcost[i][j-],maxcost[e][j-]);
}
}
}
} int cal(int n,int m)
{
memset(maxcost, , sizeof(maxcost));
memset(far, , sizeof(far));
memset(level, , sizeof(level));
memset(anc, 0x8f, sizeof(anc));
//kruscal
for(int i=; i<=n; i++)
{
pre[i]=i;
cost[i].clear();
vect[i].clear();
}
for(int i=; i<m; i++)
{
int u=find( a[seq[i]] );
int v=find( b[seq[i]] );
if(u!=v)
{
pre[u]=v;
vect[a[seq[i]]].push_back(b[seq[i]]);
vect[b[seq[i]]].push_back(a[seq[i]]);
cost[a[seq[i]]][b[seq[i]]]=w[seq[i]]; //因为目前还不知道谁是父亲
cost[b[seq[i]]][a[seq[i]]]=w[seq[i]];
}
}
//dfs
memset(vis, , sizeof(vis));
DFS(, );
preprocess(n);
return ;
} int query(int p,int q) //先找LCA,再求答案
{
int tmp, log, i;
if(level[p]<level[q]) swap(p,q); for(log=; (<<log)<=level[p]; log++);
--log;
int ans=-;
for(int i=log; i>=; i--)
{
if(level[p]-(<<i)>=level[q])
{
ans=max(ans, maxcost[p][i]);
p=anc[p][i];
}
} if(p==q) return ans; for(int i=log; i>=; i--)
{
if(anc[p][i]> && anc[p][i]!=anc[q][i] )
{
ans=max(ans, maxcost[p][i]);
p=anc[p][i];
ans=max(ans, maxcost[q][i]);
q=anc[q][i];
}
}
ans=max(ans, cost[p][far[p]]);
ans=max(ans, cost[q][far[q]]);
return ans;
} int main()
{
freopen("input.txt", "r", stdin);
int n, m, q, x, y, k=; while(~scanf("%d%d",&n,&m))
{
if(k!=) printf("\n");//格式
k++;
for(int i=; i<m; i++)
{
seq[i]=i; //边号
scanf("%d%d%d", &a[i], &b[i], &w[i]);
}
sort(seq, seq+m, cmp);
cal(n, m);
scanf("%d",&q);
for(int i=; i<q; i++)
{
scanf("%d%d",&x,&y);
printf("%d\n", query(x,y));
}
}
return ;
}

AC代码

UVA 11354 Bond 邦德 (RMQ,最小瓶颈MST)的更多相关文章

  1. UVa 11354 邦德(最小瓶颈路+LCA)

    https://vjudge.net/problem/UVA-11354 题意: 有n个城市m条道路,每条道路有一个危险系数.先在有若干个询问,要求找到一条从s到t的路,使得途径所有边的最大危险系数最 ...

  2. uva 11354 - Bond(树链拆分)

    题目链接:uva 11354 - Bond 题目大意:给定一张图.每次询问两个节点路径上进过边的危急值的最大值的最小值. 解题思路:首先建立最小生成数,然后依据这棵树做树链剖分. #include & ...

  3. UVA 11354 Bond(最小瓶颈路+倍增)

    题意:问图上任意两点(u,v)之间的路径上,所经过的最大边权最小为多少? 求最小瓶颈路,既是求最小生成树.因为要处理多组询问,所以需要用倍增加速. 先处理出最小生成树,prim的时间复杂度为O(n*n ...

  4. uva 11354 Bond

    题意: 邦德在逃命!他在一个有N个城市,由M条边连接的道路网中.一条路的危险度被定义为这条路上危险度最大的边的危险度. 现在给出若干个询问,s,t,问从s到t的最小的危险度是多少. 思路: 首先可以证 ...

  5. 【uva 534】Frogger(图论--最小瓶颈路 模版题)

    题意:平面上有N个石头,给出坐标.一只青蛙从1号石头跳到2号石头,使路径上的最长便最短.输出这个值.(2≤N≤200) 解法:最小瓶颈树.而由于这题N比较小便可以用2种方法:1.最短路径中提到过的Fl ...

  6. UVA - 11354 Bond(最小生成树+LCA+瓶颈路)

    题意:N个点,M条路,每条路的危险度为路上各段中最大的危险度.多组询问,点s到点t的所有路径中最小的危险度. 分析: 1.首先建个最小生成树,则s到t的路径一定是危险度最小的. 原因:建最小生成树的最 ...

  7. UVA 11354 Bond(MST + LCA)

    n<=50000, m<=100000的无向图,对于Q<=50000个询问,每次求q->p的瓶颈路. 其实求瓶颈路数组maxcost[u][v]有用邻接矩阵prim的方法.但是 ...

  8. UVA 11354 - Bond (最小生成树 + 树链剖分)

    题目链接~~> 做题感悟:这题開始看到时感觉不是树不优点理,一想能够用 Kruskal 处理成树 ,然后就好攻克了. 解题思路: 先用 Kruskal 处理出最小生成树.然后用树链剖分 + 线段 ...

  9. UVA 11354 Bond 最小生成树 + lca

    题意 给出一张图,q个询问,每次询问给出uv,找出一条路径,使这条路径上的最大边权是两点所有路径中最小,输出这个值 思路 很显然要先求出最小生成树,任意两点在最小生成树上有唯一路径,并且这条路径上的最 ...

随机推荐

  1. POJ 3233 Matrix Power Series (矩阵快速幂+二分求解)

    题意:求S=(A+A^2+A^3+...+A^k)%m的和 方法一:二分求解S=A+A^2+...+A^k若k为奇数:S=(A+A^2+...+A^(k/2))+A^(k/2)*(A+A^2+...+ ...

  2. Android的事件处理机制(一)------基于回调机制的事件处理

    Android平台的事件处理机制有两种,一种是基于回调机制的,一种是基于监听接口的,现介绍第一种:基于回调机制的事件处理.Android平台中,每个View都有自己的处理事件的回调方法,开发人员可以通 ...

  3. (转)Android之ListView原理学习与优化总结

    转自: http://jishu.zol.com.cn/12893.html 在整理前几篇文章的时候有朋友提出写一下ListView的性能优化方面的东西,这个问题也是小马在面试过程中被别人问到的….. ...

  4. jenkins配置及使用中出现的问题

    安装中遇到的问题: 1.linux中最好用普通用户安装tomcat和jenkins,用普通用户启动tomcat,否则jenkins工作空间不会在普通用户下,而线上自动发布部署时,是不允许用root用户 ...

  5. lintcode:打劫房屋 III

    题目 打劫房屋 III 在上次打劫完一条街道之后和一圈房屋之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子组成的区域比较奇怪,聪明的窃贼考察地形之后,发现这次的地形是一颗二叉树.与前两次偷窃 ...

  6. Android核心分析之十九电话系统之GSMCallTacker

    GSMCallTracker在本质上是一个Handler.<IGNORE_JS_OP> 1.jpg (1.52 KB, 下载次数: 1) 下载附件  保存到相册 2012-3-22 11: ...

  7. 天使投资、VC 以及 PE 的区别是什么?

    如果满足于“阶段不同”这个简单的回答,那你可能错过了一个思考资本与企业发展之间关系的机会. 首先要交待一下,在大众语境中,angel/VC/PE三者都可认为是VC,也就是人们常说的风险投资,在国内官方 ...

  8. ExtJs计算两个DateField所间隔的月份(天数) new Date(str) IE游览器提示NaN 处理

    需求:两个DateField控件,分别为开始时间和结束时间.当选择完结束时间后,自动计算这两个时间段所间隔的月或天数. 需要解决的问题: 1.直接使用Ext.getCmp('endDate').get ...

  9. SSIS -->> Data Type

    SSIS和SQL SERVER, .NET数据类型的映射表

  10. c# 任意多个数,求最大值

    c#  任意多个数,求最大值 使用parms: 正在研究中,如果有好的方案,可评论,共同进步,共同提高,谢谢!