生活随笔
收集整理的這篇文章主要介紹了
HDU 3938 Portal
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
找兩點間最長邊(一條路徑)的最小值(所有路徑),這個值的意義在本題中相當于這兩點可以在某種意義上連通了,然后給定一個值L問你最多能連通多少種兩點。
需要注意的是L不是和的上限,而是單個兩點間費用的上限。所以只用想有多少種兩點間的費用小于等于L就行了。
而兩點間的費用必然等于某條邊的權值。
要知道,邊的權值按從小到大離散分布,那么L可以退化到某個小于等于它的邊的權值上。
所以,每次union返回的是本次union帶來全圖新增的連通的兩點對的個數,是增量。那么本次邊的權值所對應的查詢結果就是歷史連通對個數加上本次增量。
由于邊的權值范圍太大,用unordered_map替代數組。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <unordered_map>
using namespace std;
const int MAXN =
1e4 +
5;
int N, M, Q;
int pre[MAXN];
unordered_map<int, int> mk;
struct Edge
{
int n1, n2, cost;
bool operator<(
const Edge& e)
const{
return cost < e.cost;}
};
vector<Edge> ve;
void init()
{ve.clear();
memset(pre, -
1,
sizeof pre);mk.clear();
}
int f(
int x)
{
int f0 = x, f1 = x;
for (; pre[f0] >
0;) f0 = pre[f0];
for (; pre[f1] >
0;){
int t = f1;f1 = pre[f1];pre[t] = f0;}
return f0;
}
int u(
int n1,
int n2)
{
int f1 = f(n1);
int f2 = f(n2);
if (f1 != f2){
int t = -(pre[f1] + pre[f2]);
int r = (t*(t -
1)) /
2 - ((-pre[f1] * (-pre[f1] -
1)) /
2 + (-pre[f2] * (-pre[f2] -
1)) /
2);
if (pre[f1] <= pre[f2]){pre[f1] += pre[f2];pre[f2] = f1;}
else{pre[f2] += pre[f1];pre[f1] = f2;}
return r;}
return 0;
}
int main()
{
int a, b, c;
for (; ~
scanf(
"%d%d%d", &N, &M, &Q);){init();
for (
int i =
0; i < M; i++){
scanf(
"%d%d%d", &a, &b, &c);ve.push_back({ a,b,c });}sort(ve.begin(), ve.end());
int total =
0;
for (
int i =
0; i < ve.size(); i++){total += u(ve[i].n1, ve[i].n2);mk[ve[i].cost] = total;}
for (
int i =
0; i < Q; i++){
scanf(
"%d", &a);
int ans =
0;
for (
int j = a; j >=
0; j--){
if (mk.find(j) != mk.end()){mk[a] = mk[j];ans = mk[j];
break;}}
printf(
"%d\n", ans);}}
return 0;
}
轉載于:https://www.cnblogs.com/CrossingOver/p/10704889.html
總結
以上是生活随笔為你收集整理的HDU 3938 Portal的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。