luogu2680 運輸計畫

2022-05-07 23:15:20 字數 1488 閱讀 3421

​ 很明顯, 由於是求最長路的最小值, 我們可以使用二分求解. 我們二分乙個長度\(mid\), 將所有使得\(dis(u, v)\)大於\(mid\)的點對\((u, v)\)找出, 設總共有\(m\)條這樣的邊, 那麼我們需要改變的改變邊一定是被這\(m\)條邊都經過的邊, 所以我們只需要找到滿足這個要求的長度最大的改變邊使得這\(m\)條邊中最長的一條減去這一條改變邊小於等於\(mid\) 就可以了, 如果沒有這樣的邊就說明\(mid\)小了. 那要怎麼找這條改變邊呢??? 樹上差分就可以了啊, 將邊權下放為點權, 讓\(cnt[u]++\), \(cnt[v]++\), \(cnt[lca(u, v)] -= 2\)就可以了, 至於某個點被經過的次數就將他子樹的累加起來即可.

#include #include #include #include #define n 300005

using namespace std;

int n, m, head[n], tot, fa[n], cost[n], road[n], cnt, num[n], vis[n], l, r, mid, ans;

struct node

edge[n << 1];

struct ask

ask[n];

struct node2

; vectorlca[n];

inline int read()

while(c >= '0' && c <= '9')

return x * w;

}inline void add(int u, int v, int w)

int find(int x)

void tarjan(int u, int ff)

for(int i = 0; i < (int) lca[u].size(); i++)

if(vis[lca[u][i].v] && !ask[lca[u][i].id].lca)

ask[lca[u][i].id].lca = find(lca[u][i].v);

}void dfs(int u, int fa)

}bool check(int mid)

dfs(1, 0);

for(int i = 1; i <= n; i++)

if(num[i] >= sum && mx - cost[i] <= mid) return 1;

return 0;

}int main()

for(int i = 1; i <= m; i++)

); lca[ask[i].v].push_back((node2));

} tarjan(1, 0);

for(int i = 1; i <= m; i++)

ans = r;

while(l <= r)

else l = mid + 1;

} printf("%d\n", ans);

return 0;

}

Luogu2680 運輸計畫

我們對每條邊 i 單獨考慮,那麼設 v i 為這條邊的長度,經過它的路徑長度集合為 s 未經過它的路徑長度集合為 t ans i max begin s v i t end ans min ans i 對於 s 我們直接對於一條長度為 l 的路徑,該路徑上的邊都對 l 取 max 用樹鏈剖分很容易處...

luogu2680 運輸計畫

首先二分列舉答案t,考慮刪去的邊應滿足的條件 所有大於 t的鏈全部經過且長度不小於最長鏈 t,第二個條件很好判斷,考慮第乙個條件。先考慮有祖先 後代關係的鏈,用如果把這條鏈到 1看成乙個序列,那麼差分一下再 dfs一遍就可以對這條鏈上每乙個點打上標記。然後沒有祖先 後代關係的鏈,同樣可以分解成兩條鏈...

題解 LuoGu2680 運輸計畫

原題傳送門 去年覺得是道難題,現在覺得這著實是道大水題 題意 一棵樹,給出幾條路徑 從點x到點y 可以使一條邊長度變為0,使得路徑長度最大值最小 思路 就搞定了 接著想如何實現 總結 noip的題目還是很可以的,演算法 思維難度不高,應用性還是比較強的 用到了許多小演算法 lca,二分,樹上差分 c...