題目:
分析:1、首先建立最大生成樹(可能是森林),常用的是kruskal演算法,需要借助並查集,採用前向星儲存mst。
2、上面的mst是無根的,需要轉換成有根的。引入三個陣列。deep[i]——結點i的深度;f[i][j]——結點i的2^j的遠祖;g[i][j]——結點i到它的2^j的遠祖路徑上的瓶頸值。在建樹的過程中採用遞推的方法求出d,f,g。
3、lca查詢x到y路徑上的瓶頸值。lca分三個經典步驟:一是用x表示深度大的點;二是move,用倍增的方法將x的深度調成與y一樣,如果更新的後的x=y,則對應的min即是所求(乙個細節);三是倍增求出最近公共祖先,有兩個細節需要注意。詳見**說明。
關於樹上倍增求lca的說明:
一、打表:(for要求順序)
用f[x][i]表示點x的2^i遠的祖先,有遞推式f[x][i]=f[ f[x][i-1] ][i-1],遍歷所有點,求出所有點的2^i的祖先,其中i=0..20。
二、查表:(for要求逆序)
1、用x表示深度大的點;
2、如果deep[x]!=deep[y],用倍增方法使得deep[x]=deep[y],如果x=y,則return lca=x(細節);
3、用倍增方法同步往上找,如果f[x][i]!=f[y][i](細節),則令x=f[x][i],y=f[y][i],結束查表後的x與y是lca的兒子,
故需要 return f[x][0](細節)。
ac**:
#include#include#include#include#includeusing namespace std;
int n,m,q,head[10005],num,fat[10005];
bool vis[10005]=;
int deep[10005],f[10005][21],g[10005][21];
struct t;
t a[50005];
struct edge;
edge e[100005];
int cmp( t a, t b)
void add(int from,int to,int w)
int father(int x)
void unionn(int x,int y)
void kurskal()
}}void build_tree(int u)
for(int i=head[u];i!=-1;i=e[i].next)
}}int move(int &u,int h)
}return minn;
}int lca(int x,int y)
}
}if(x==y)return minn;//細節:重要,否則與下面for之後min所在行**衝突
for(int i=20;i>=0;i--)
if(f[x][i]!=f[y][i])
minn=min(minn,min(g[x][0],g[y][0]));//細節:注意:前面的for結束後x!=y
return minn;
}int main()
//查詢
cin>>q;
for(int x,y,i=1;i<=q;i++)
return 0;
}
洛谷 P1967 貨車運輸
a 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。輸入檔名為 truck.in。輸入檔案第一行有兩個用乙個空格隔開的整數 n,m,表示 a 國有 ...
洛谷 P1967 貨車運輸
題目描述 a 國有 n 座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物,司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。輸入輸出格式 輸入格式 輸入檔名為 truck.in。輸入檔案第一行有兩個用乙個空格隔...
貨車運輸 洛谷p1967
解法一 30分 直接跑spfa,求最大瓶頸路。include include include define f i,l,r for i l i r i using namespace std const int maxn 10005,maxm 50005,inf 100000000 struct e...