【LCA+MST】BZOJ3732-Network

【题目大意】

给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。图中有M条边 (1<=M<=30,000) ,第j条边的长度:d_j (1<=d_j <=1,000,000,000)。现在有 K个询问 (1 < = K < = 15,000), 每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

【思路】

显然,最小的最长边应该在MST上。先跑出MST,然后对于每个询问跑LCA,在跑LCA的过程中顺便处理最长边。

LCA处理最长边是第一次写,但是这种东西,yy一下就好了,和LCA里面的祖先数组长得是一样的啊……

【错误点】

LCA是最后a的父亲,所以我们还要比较一下a和它父亲的连边……

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int MAXN=15000+50;
  4 const int MAXM=30000+50;
  5 const int DEG=20;
  6 struct Edge
  7 {
  8     int u,v,w;
  9     bool operator < (const Edge &x) const
 10     {
 11         return w<x.w;
 12     };
 13 };
 14 Edge edge[MAXM];
 15 vector<Edge> E[MAXN];
 16 int n,m,k;
 17 int u[MAXN],h[MAXN];
 18 int dep[MAXN],anc[MAXN][DEG],maxlen[MAXN][DEG];
 19 
 20 void addedge(int u,int v,int w)
 21 {
 22     E[u].push_back((Edge){u,v,w});
 23     E[v].push_back((Edge){v,u,w});
 24 }
 25 
 26 int find(int x)
 27 {
 28     int r=x;
 29     while (u[r]!=r) r=u[r];
 30     int tmp;
 31     while (u[x]!=x)
 32     {
 33         tmp=u[x];
 34         u[x]=r;
 35         x=tmp;
 36     }
 37     return r;
 38 }
 39 
 40 void union_set(int fa,int fb)
 41 {
 42     if (h[fa]>=h[fb])
 43     {
 44         u[fb]=fa;
 45         if (h[fa]==h[fb]) h[fa]++;
 46     }
 47     else u[fa]=fb;
 48 }
 49 
 50 void dfs(int u,int fa,int d)
 51 {
 52     anc[u][0]=fa;
 53     dep[u]=d;
 54     for (int i=0;i<E[u].size();i++)
 55     {
 56         int to=E[u][i].v;
 57         if (to==fa) continue;
 58         maxlen[to][0]=E[u][i].w;
 59         dfs(to,u,d+1);
 60     }
 61 }
 62 
 63 void getanc()
 64 {
 65     for (int i=1;i<DEG;i++)
 66         for (int j=1;j<=n;j++)
 67         {
 68             anc[j][i]=anc[anc[j][i-1]][i-1];
 69             maxlen[j][i]=max(maxlen[j][i-1],maxlen[anc[j][i-1]][i-1]);
 70         }
 71 }
 72 
 73 int swim(int x,int H,int &ret)
 74 {
 75     for (int i=0;H>0;i++)
 76     {
 77         if (H&1) ret=max(ret,maxlen[x][i]),x=anc[x][i];//swim过程中不要忘记更新ret 
 78         H/=2;
 79     }
 80     return x;
 81 }
 82 
 83 int lca(int a,int b)
 84 {
 85     int ret=-1;
 86     if (dep[a]<dep[b]) swap(a,b);
 87     a=swim(a,dep[a]-dep[b],ret);
 88     if (a==b) return ret;
 89     for (int i=DEG-1;i>=0;i--)
 90     {
 91         if (anc[a][i]!=anc[b][i])
 92         {
 93             ret=max(ret,maxlen[a][i]);
 94             a=anc[a][i];
 95             ret=max(ret,maxlen[b][i]);
 96             b=anc[b][i];
 97         }
 98     }
 99     ret=max(ret,maxlen[a][0]);//最后一条和父亲的连边不要忘记 
100     ret=max(ret,maxlen[b][0]);
101     return (ret);
102 }
103 
104 
105 void init()
106 {
107     scanf("%d%d%d",&n,&m,&k);
108     for (int i=1;i<=m;i++)
109         scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
110     for (int i=1;i<=n;i++) u[i]=i,h[i]=1;
111 }
112 
113 void kruskal()
114 {
115     sort(edge+1,edge+m+1);
116     for (int i=1;i<=m;i++)
117     {
118         int a=edge[i].u,b=edge[i].v;
119         int fa=find(a),fb=find(b);
120         if (fa!=fb)
121         {
122             union_set(fa,fb);
123             addedge(edge[i].u,edge[i].v,edge[i].w);
124         }
125     }
126 }
127 
128 void query()
129 {
130     dfs(1,0,1); 
131     getanc();
132     for (int i=0;i<k;i++)
133     {
134         int a,b;
135         scanf("%d%d",&a,&b);
136         printf("%d\n",lca(a,b));
137     }
138 }
139 
140 int main()
141 {
142     init();
143     kruskal();
144     query();
145     return 0;
146 } 

 

posted @ 2016-11-16 22:43  iiyiyi  阅读(235)  评论(0编辑  收藏  举报