uva11354 LCA+最小生成树+dp

源自大白书

题意 有n座城市通过m条双向道路相连,每条道路都有一个危险系数。你的任务是回答若干个询问,每个询问包含一个起点s和一个终点t,要求找到一条从s到t的路,使得途径所有的边的大最大危险系数最小。

解: 首先求出最小生成树,并把它改写成有根树,让fa[i]和cost[i]分别表示节点i的父亲编号和它与父亲之间的边权,L[i]表示节点i的深度,接下来通过预处理计算出数组anc 和 maxcost 其中anc[i][j] 表示节点i的2^j 级祖先的编号 macost[i][j] 表示i到2^j级 祖先之间的最大权值。

有了预处理 私用LCA 来查询结果, 查询p,q, 并且p比q深, 则可以先把p提升到和q处于同一级的位置,然后用二进制展开的方法不断把p和q同时往上提(保证二者深度相等),同时更新最大的边权

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <string.h>
  5 #include <vector>
  6 using namespace std;
  7 const int maxn = 50000+10;
  8 const int INF =2000000000;
  9 struct Edge{
 10    int from,to, dist;
 11    bool operator <(const Edge & rhs)const{
 12        return dist<rhs.dist;
 13    }
 14 }E[maxn*2];
 15 struct ed{
 16   int to,dist;
 17 };
 18 vector<ed> G[maxn];
 19 int fa[maxn],per[maxn],cost[maxn],L[maxn];
 20 int anc[maxn][20],maxcost[maxn][20];
 21 void inti(int n){
 22     for(int i =0; i<n; i++){
 23          per[i] = i;
 24          G[i].clear();
 25     }
 26 }
 27 void preprocess( int n){
 28     for(int i=0; i<n ; i++){
 29            anc[i][0] = fa[i]; maxcost[i][0]=cost[i];
 30            for(int j=1; (1<<j)<n; j++) anc[i][j]=-1;
 31     }
 32     for(int j =1; (1<<j)<n; j++)
 33         for(int i=0; i<n; i++){
 34         if(anc[i][j-1]!=-1){
 35               int a = anc[i][j-1];
 36               anc[i][j]=anc[a][j-1];
 37               maxcost[i][j] = max(maxcost[i][j-1],maxcost[a][j-1]);
 38         }
 39     }
 40 }
 41 int fid(int u){
 42    return per[u]==u?u:(per[u]= fid(per[u]));
 43 }
 44 void dfs(int u, int p,int dist, int depth){
 45      fa[u]=p; cost[u] = dist; L[u] = depth;
 46      for(int i = 0; i<(int)G[u].size(); ++i){
 47           ed e = G[u][i];
 48           if(e.to == p) continue;
 49           dfs(e.to,u,e.dist,depth+1);
 50      }
 51 }
 52 int query(int p, int q){
 53     int log;
 54     if(L[p]<L[q]) swap(p,q);
 55     for( log =1; (1<<log)<=L[p]; log++); log--;
 56     int ans=-INF;
 57     for(int i = log ; i>=0; i--)
 58     if( L[p] - (1<<i) >= L[q] ){
 59         ans = max(ans,maxcost[p][i]);
 60         p = anc[p][i];
 61     }
 62     if(p==q) return ans;
 63     for(int i=log; i>=0; i--)
 64     if(anc[p][i]!=-1 && anc[p][i]!=anc[q][i]){
 65          ans = max(ans,maxcost[p][i]); p = anc[p][i];
 66          ans = max(ans,maxcost[q][i]); q = anc[q][i];
 67     }
 68     ans = max(ans,cost[p]);
 69     ans = max(ans,cost[q]);
 70     return ans;
 71 }
 72 int main()
 73 {
 74     int n,m,f=0;
 75     while(scanf("%d%d",&n,&m)==2){
 76          inti(n);
 77          for(int i=0; i<m ; i++){
 78              int x,y,d;
 79              scanf("%d%d%d",&x,&y,&d);
 80              x--,y--;
 81              E[i]=(Edge){x,y,d};
 82          }
 83          int lest = n;
 84          sort(E,E+m);
 85          for(int i=0; i<m; i++){
 86              int a = E[i].from,b=E[i].to, dist= E[i].dist;
 87              int ca = fid(a),cb = fid(b);
 88              if(ca!=cb){
 89                   per[ca] =cb;
 90                   lest--;
 91                   G[a].push_back((ed){b,dist} );
 92                   G[b].push_back((ed){a,dist} );
 93                   if(lest==1) break;
 94              }
 95          }
 96          dfs(0,-1,0,0);
 97          preprocess(n);
 98           int Q;
 99          if(f)
100             puts("");
101          else f=1;
102           scanf("%d",&Q);
103           for(int i =0; i<Q; i++){
104                int s,t;
105                scanf("%d%d",&s,&t);
106                s--;t--;
107               printf("%d\n",query(s,t));
108           }
109 
110     }
111 
112     return 0;
113 }

 

posted @ 2015-03-25 20:13  来自大山深处的菜鸟  阅读(203)  评论(0编辑  收藏  举报