首先說這道題的思路:存在多條路徑時求路徑最大權的最小值問題,可以利用生成樹的性質重建給出的圖,將多路徑轉化為一定最優的單一路徑,再在樹上求lca時統計權值來求出「路徑最大權的最小值」。
寫這份**的時候複習了幾個重要的知識點:
並查集在寫生成樹時,經常會用到並查集。
ll find
(ll x)
並查集的**非常簡單,需要注意的是,在合併時,語句為:
f[
find
(x)]
=find
(y);
而不是:
f[x]
=find
(y);
下面的寫法會漏合併x所在的集合的其他點 (我在這裡卡了是真的丟人)
lca這道題中的lca與一般的lca大同小異,只是在求2
i2^i
2i級父節點時一起將到2
i2^i
2i級父節點的「路徑最大權的最小值」一起求出來,在倍增求lca時也加入統計「路徑最大權的最小值」的**即可。同時,由於這道題可能給出森林,因此需要將每個點都作為根來dfs,同時加入特判來判定某個點是否已經屬於某棵已知的樹。
void
dfs(ll k,ll fa)
for(
int i=head[k]
;i;i=l[i]
.n)}
ll lca
(ll u,ll p)
if(u==p)
return ans;
for(
int i=
19;i>=
0;i--)}
ans=
min(ans,
min(w[u][0
],w[p][0
]));
//統計「路徑最大權的最小值」
return ans;
}
其他重要操作還有前向星和生成樹,不過這些較為簡單,就不再贅述,**見下方即可。
ac**:
#include
#include
#define ll long long
using namespace std;
const
int maxn=
1e5+5;
ll n,m,x,y,z,q;
ll b[maxn]
;//並查集
ll head[maxn]
,ecnt=1;
//前向星
ll v[maxn]
,f[maxn][20
],d[maxn]
;//lca
ll w[maxn][20
];//lca中到父節點的最小邊權
struct edgee[maxn]
;struct listl[maxn]
;bool cmp
(edge a,edge b)
ll find
(ll x)
void
swap
(int
&a,int
&b)void
add(ll a,ll b,ll c)
void
scs()}
}void
dfs(ll k,ll fa)
for(
int i=head[k]
;i;i=l[i]
.n)}
ll lca
(ll u,ll p)
if(u==p)
return ans;
for(
int i=
19;i>=
0;i--)}
ans=
min(ans,
min(w[u][0
],w[p][0
]));
return ans;
}/*void out()
}*/int
main()
return0;
}
以及,善用注釋! 洛谷 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...