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;
}