我是真的不穩定的垃圾選手。
對於一張圖來說,兩個人能滿足題面關係等價於這張圖不是鏈,很好證明,如果有度數 \(> 2\) 的點,讓乙個人跑到乙個度數 \(= 1\) 的地方就可以了。
如果離線就可以什麼啟發式合併 + 並查集做到乙個 \(\log\)。就是合併兩個點 \(x, y\),動態維護每個聯通塊是不是鏈。
#include #include #include using namespace std;
const int maxn = 100005, maxm = 200005;
int n, m, arr[maxm], tot;
struct e
} e[maxm];
struct t;
struct array
int mid = (l + r) >> 1;
build(t[p].l, l, mid, o);
build(t[p].r, mid + 1, r, o);
} void update(int &p, int q, int l, int r, int x, int o)
int mid = (l + r) >> 1;
if (x <= mid) update(t[p].l, t[q].l, l, mid, x, o);
else update(t[p].r, t[q].r, mid + 1, r, x, o);
} int query(int p, int l, int r, int x)
void inline set(int x, int k, int i)
int inline get(int x, int i)
} p, f, d, sz;
int find(int x, int i)
void inline merge(int x, int y, int i) else
}void init(int n, int m,
std::vectoru, std::vectorv, std::vectorw) ;
} sort(arr + 1, arr + 1 + tot);
tot = unique(arr + 1, arr + 1 + tot) - arr - 1;
sort(e, e + m);
f.build(f.rt[0], 0, n - 1, -1), sz.build(sz.rt[0], 0, n - 1, 1);
p.build(p.rt[0], 0, n - 1, 0), d.build(d.rt[0], 0, n - 1, 1);
for (int i = 1, j = 0; i <= tot; i++) }}
bool inline check(int x, int y, int i)
int getminimumfuelcapacity(int x, int y)
return arr[r];
}
然後就去無恥的看題解,然後去學了一下 kruscal 重構樹。
我們不妨設計乙個特殊的 kruscal 重構樹,使得對於 \(x, y\) 的詢問,答案就是他們的 lca ,即他們的 lca 是合併過程中讓他們從鏈變成不是鏈的那條關鍵邊!
那麼,設計一種類似於普通 kruscal 最小重構樹的方式,只不過改動如下:
發現這麼構造仍然滿足大根堆性質。
用啟發式合併儲存當前聯通塊的所有點,每個原始點只會連一次,即連向他所在聯通塊轉變的關鍵邊新點,所以複雜度是 \(o(n \log n)\) 的。
正確性:在 lca 這個子樹中,所有邊都是 \(\le w_\) 的,lca 的子樹形成的結構不是鏈,因為只有不是鏈才會連邊,所以必然 lca 的權值是可以的。然後證明 \(ans \ge w_\)。\(ans < w_\) 顯然是不行的,因為他們要用這條關鍵邊。所以 \(ans = w_\)。
所以每次詢問求個 lca 就行了。
時間複雜度 \(o((n + q) \log n)\)
我**偷了一下懶,即只在鏈的時候維護各種資訊,已經不是鏈了,除了 \(f\) 陣列剩下就不用維護。
#include "swap.h"
#include #include #include using namespace std;
const int n = 100005, m = 200005, l = 19;
int n, m, f[n << 1], fa[n << 1][l], dep[n << 1], cnt, sz[n], a[n << 1];
bool ch[n << 1], d[n];
vectorg[n << 1];
vectorc[n << 1];
struct e
} e[m];
int find(int x)
void dfs(int u)
}int lca(int x, int y)
void inline merge(int u, int v, int w)
} else else
}}void init(int n, int m, std::vectoru, std::vectorv, std::vectorw) ;
sort(e + 1, e + 1 + m);
for (int i = 1; i < 2 * n; i++)
for (int i = 1; i <= m; i++) merge(e[i].u, e[i].v, e[i].w);
if (cnt > n)
dfs(cnt);
}int getminimumfuelcapacity(int x, int y)
APIO2020 粉刷牆壁
考場想了 5.5 h,第一部分分死活打不出來,做到崩盤,現在重做,感覺自己就是乙個sb,放學在地鐵上一眼就會了。哎。可以把乙個要求看作乙個長度為 m 的區間 l,l m 1 可以要求這段條件的充要條件是找到一種迴圈移位,每個牆恰好可以被那個工人挖。然後問題是用最少的區間覆蓋完 0,n 1 可以設乙個...
網易2020筆試真題 序列交換
題目描述 小易給你乙個包含n個數字的陣列a1,a2,an。你可以對這個陣列執行任意以下交換操作 對於陣列中的兩個下標i,j 1 i,j n 如果ai aj為奇數,就可以交換ai和aj 現在允許你使用操作次數不限,小易希望你能求出在所有通過若干次操作可以得到的陣列中,字典序最小的乙個是什麼 輸入描述 ...
布局智慧型城市建設,2020高交會雲天勵飛創新謀變
今日,第二十二屆高交會順利在深圳拉開帷幕,高交會被譽為 中國科技第一展 也是科技創新成果集中展示的最大平台。在本屆高交會上,雲天勵飛展出了 新基建 雲天勵飛城市智慧型體 ai疫情態勢感知系統 ai書城智慧型屏 等產品和解決方案,吸引了眾多參觀者駐足 最受關注 ai疫情防控平台 今年,新冠疫情肆虐全球...