洛谷 P1967 貨車運輸

2022-06-01 10:51:12 字數 2760 閱讀 4047

updata 1.22:附上樹鏈剖分的**,

前置知識 :

思路:

觀察題目,發現司機們並不管送貨路程的遠近,只管能裝貨物的總數。如果有一條比較遠的路,但能裝貨物的總量更大,司機還是會繞道走的。由此來看,一些較小的邊是不會被走到的(除了沒有其他路可走),於是我們只需要在保證在沒有破壞圖的連通性的條件下(但題目沒說圖一開始就是連通的)刪掉較小的邊。完成以上操作,我們只需先建立乙個最大生成樹即可(注意先把圖的資料存起來,然後邊跑 $kruskal$ 邊將確定的邊再連上),其實也是方便完成 $step2$ 的操作罷了。

操作方式 :處理最大生成樹的方法和處理最小生成樹的方法等同(千萬不要把 $cmp$ 裡的大於號小於號給寫反了),只不過要在 $kruskal$ 中把已經確定的邊連上,$warning$ —— 是雙向邊。

處理完了圖的操作後,我們思考如何將司機所能運輸的最大載貨量給求出來,同時,看資料,加上外層的一層迴圈,只能用 $log(n)$ 的複雜度求出路徑上的距離, $lca$ 恰恰是如此。在處理點深度和父節點時,可以像 $fa[u][i]$ 一樣建立乙個 $q[u][i]$ ,表示從$u$到$u$的第 $2$i 個祖先上的路徑的最小邊權是多少(但這裡邊權存在深度較深的那個節點上面了)。然後邊跑 $lca$ 在起點和終點向上「跳」時進行更新 $ans$,及 $ans$ $=$ $min(ans$, $min(q[x][i]$, $q[y][i]))$,還有在 $x$,$y$中較深的節點向上「跳」時,也需要更新 $ans$,及 $ans$ $=$ $min(ans$, $q[u][i])$。當然,在初始化深度和 $fa$ 陣列的時候,也需要處理一下 $q$ 陣列的初始化,及 $q[u][i]$ $=$ $min(q[u][i$ $-$ $1]$, $q[fa[u][i$ $-$ $1]][i$ $-$ $1])$。然後,就只需要邊跑 $lca$ 邊更新答案就好了。

操作方式 :正常 $lca$ $+$ 更新 $q$ 陣列與 $ans$。

1 #include 2

#define inf 0x3f3f3f3f

3using

namespace

std;

4int n, m, p, head[1000001], num, depth[1000001], fa[1000001][21], q[1000001][21], fa[1000001], size[1000001];//

size陣列是按秩合併裡需要的,可以不管

5struct

node

6stu[2000001];9

struct

node

10tree[2000001];//

kruskal裡需要用到的陣列

13 inline int

cmp(node a, node b)

1417 inline void add(int x, int y, int z)//

加邊 18

25 inline int find(int x)//

查詢 26

29 inline void unity(int x, int y)//

按秩合併

3038

else

3943

return;44

}45 inline void kruskal()//

最大生成樹

4661}62

}63return;64

}65 inline void dfs(int u, int father, int value)//

value是邊權,存在深度深的節點上面

6676

for(register int i = head[u]; i; i =stu[i].next)

7783}84

return;85

}86 inline void up(int &u, int step, int &ans)//

將深度跳到相同位置

8796}97

return;98

}99 inline int lca(int x, int y)//

lca

100105

int ans =inf;

106if(depth[x] 107110 up(x, depth[x] -depth[y], ans);

111if(x ==y)

112115

int maxn = ceil(log(depth[x]) / log(2

));116

for(register int i = maxn; i >= 0; --i)

117124

}125

return min(ans, min(q[x][0], q[y][0]));//

最後父節點別忘了

126}

127signed main()

128135

for(register int i = 1, x, y, z; i <= m; ++i)

136139

kruskal();

140for(register int i = 1; i <= n; ++i)//

注意該圖可能不連通,於是需要多次dfs初始化

141146

}147 scanf("

%d", &p);

148for(register int i = 1, x, y; i <= p; ++i)

149153

return0;

154 }

洛谷 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...