Uva 11354
题意是给出n个点,m条边的图,并有q个询问(s,t),输出s到t的最右路径下的最大边权值。
用Kruskal先求出最小瓶颈生成树,并深搜将其转化为有根树,并在同时记录下每个点的深度和父结点。计算出anc[i][j]以及maxcost[i][j],分别表示i的第2^j级祖先,i到其第2^j级祖先的最长边长度,j=0时表示父节点。
那么存在递推关系anc[i][j]=anc[anc[i][j-1]][j-1],
maxcost[i][j]=max(maxcost[i][j-1],maxcost[anc[i][j-1]][j-1])。在n*lg(n)的时间里处理出这两个数组。
询问时,输入u,v。假设u深度比v深,先将u提升至与v同高,并在提升的过程中记录下最大边,再将u,v同时提升,直至他们有相同的父节点。具体实现见Query函数,利用二进制展开的方法,能将提升的过程在O(lgn)时间内实现。
#include<map>
#include<cmath>
#include<ctime>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string>
#define LL long long
#define mm0(a) memset(a,0,sizeof(a))
#define mm(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxe=1e5+5;
const int maxn=5e4+5;
const int Inf=1e9+5;
struct Edge{
int from, to, next, dist;
int id;
Edge(){}
Edge(int a,int b,int c,int d,int e):from(a), to(b), next(c), dist(d), id(e){}
bool operator <(const Edge &rhs)const{
return dist<rhs.dist;
}
};
int n, m, ecnt;
int par[maxn], rak[maxn];
int head[maxn], intree[2*maxe];
int cost[maxn];
int anc[maxn][20], maxcost[maxn][20];
int L[maxn], F[maxn];
Edge edges[2*maxe];
void Init(int n){
ecnt=0;
mm(head,-1);
mm0(intree);
mm0(maxcost);
mm0(rak);
mm0(cost);
for(int i=0;i<n;i++)
par[i]=i;
}
void Add_Edge(int u,int v,int d){
edges[ecnt]=Edge(u, v, head[u], d, ecnt);
head[u]=ecnt++;
}
int Find(int x){
if(par[x]==x) return x;
par[x]=Find(par[x]);
return par[x];
}
void Unite(int u, int v){
int fu=Find(u);
int fv=Find(v);
if(fu==fv) return;
if(rak[fu]<rak[fv]){
par[fu]=fv;
}else{
par[fv]=fu;
rak[fu]++;
}
}
bool Cmp(Edge a,Edge b){
return a.id<b.id;
}
void Kruskal(){
sort(edges,edges+ecnt);
for(int i=0;i<ecnt;i++){
Edge &e=edges[i];
int u=e.from;
int v=e.to;
int fu=Find(u);
int fv=Find(v);
if(fu==fv) continue;
else{
intree[e.id]=1;
intree[e.id^1]=1;
Unite(u,v);
}
}
sort(edges,edges+ecnt,Cmp);
}
void Dfs(int u,int fa,int dep){
L[u]=dep, F[u]=fa;
for(int i=head[u];i!=-1;i=edges[i].next)
if(intree[i]){
Edge &e=edges[i];
if(e.to==fa) continue;
cost[e.to]=e.dist;
Dfs(e.to, u, dep+1);
}
}
void PreProcess(){
for(int i=0;i<n;i++){
anc[i][0]=F[i];
maxcost[i][0]=cost[i];
for(int j=1;(1<<j)<n;j++)
anc[i][j]=-1;
}
for(int j=1;(1<<j)<n;j++){
for(int i=0;i<n;i++)
if(anc[i][j-1]!=-1){
int x=anc[i][j-1];
anc[i][j]=anc[x][j-1];
maxcost[i][j]=max(maxcost[i][j-1],maxcost[x][j-1]);
}
}
}
int Query(int p,int q){
if(L[p]<L[q]) swap(p,q);
int log;
for(log=1;(1<<log)<=L[p];log++); log--;
int ans=-Inf;
for(int i=log;i>=0;i--)
if(L[p]-(1<<i)>=L[q]){
ans=max(ans, maxcost[p][i]);
p=anc[p][i];
}
if(p==q) return ans;
for(int i=log;i>=0;i--)
if(anc[p][i]!=-1&&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]);
ans=max(ans,cost[q]);
return ans;
}
void solve(){
}
int main(){
// freopen("matrix.in","r",stdin);//从in.txt中读取数据
// freopen("matrix.out","w",stdout);//输出到out.txt文件
int T;
int u, v, d;
int q;
int cas=0;
while(~scanf("%d%d",&n,&m)){
if(cas++!=0) puts("");
Init(n);
for(int i=0;i<m;i++){
scanf("%d%d%d",&u, &v, &d);
u--, v--;
Add_Edge(u,v,d);
Add_Edge(v,u,d);
}
Kruskal();
Dfs(0,-1,0);
PreProcess();
scanf("%d",&q);
for(int i=0;i<q;i++){
scanf("%d%d",&u,&v);
u--, v--;
printf("%d\n",Query(u,v));
}
}
return 0;
}