CF1550F Jumping Around 题解
CF1550F Jumping Around
CF1550F Jumping Around
經典的轉化,可能有點正難則反的意味。
文章目錄
- 我的思路:\textbf{我的思路:}我的思路:
- 題解:\textbf{題解:}題解:
我的思路:\textbf{我的思路:}我的思路:
可以看出因為 ddd 是不變的,所以對于一個逐漸增大的 kkk 可以到達的點是逐漸變多的,換言之就是具有單調性。
有一個比較顯然的想法,就是離線一下 kkk 考慮從小到大進行計算。考慮暴力,就是對于每一個 kkk 建圖跑一遍 Dijstra\textbf{Dijstra}Dijstra。
復雜度是 O(n2+qnlog?n)O(n^2 + q\ n\log n)O(n2+q?nlogn) 的,用一下線段樹優化建圖復雜度就是 O(qnlog?n)O(q\ n \log n)O(q?nlogn) 了。
嘗試考慮能否繼承,但是沒有結果。那么我們對于一個 kkk 進行判斷,不妨我們判斷對于一條路徑其合法需要的最小的 kkk。
題解:\textbf{題解:}題解:
我們思考對于一條路徑其最小的 kkk 就是其路徑上的最大值,也就是說我們對于任意一條路徑我們要讓其最大值最小。這就可以使用最小生成樹維護了 (也就是最小生成樹的定義)(\text{也就是最小生成樹的定義})(也就是最小生成樹的定義)。
但是發現邊數是 O(n2)O(n^2)O(n2) 級別的,直接會想到那個奇妙的 Boruvka\textbf{Boruvka}Boruvka 算法。
具體來說流程是這樣的:
- 每次合并兩個連通塊
- 合并的時候對于一個連通塊找到其連接的邊權最小的邊進行合并。
- 總共之后合并 O(log?n)O(\log n)O(logn) 次。
我們考慮如何找到最小的邊,對于一個連通塊我們需要找到和其相連的邊。不妨我們設全集為 UUU,當前連通塊的點集為 III。那么我們需要找到 min?v∈I,u∈U/I∣d?∣au?av∣∣\min_{v \in I, u \in U/I} |d - |a_u - a_v||minv∈I,u∈U/I?∣d?∣au??av?∣∣。
對于 uuu 我們使用 set\textbf{set}set 進行維護,每次刪除當前集合的所有點,之后對后面進行分類討論即可,復雜度是 O(nlog?2n)O(n \log ^ 2 n)O(nlog2n) 的。
#include <bits/stdc++.h> using namespace std;//#define Fread //#define Getmod#ifdef Fread char buf[1 << 21], *iS, *iT; #define gc() (iS == iT ? (iT = (iS = buf) + fread (buf, 1, 1 << 21, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++) #define getchar gc #endif // Freadtemplate <typename T> void r1(T &x) {x = 0;char c(getchar());int f(1);for(; c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;for(; '0' <= c && c <= '9';c = getchar()) x = (x * 10) + (c ^ 48);x *= f; }template <typename T,typename... Args> inline void r1(T& t, Args&... args) {r1(t); r1(args...); }//#define int long long const int maxn = 2e5 + 5; const int maxm = maxn << 1;int n, Q, S, d; int a[maxn]; set< pair<int, int> > s;int head[maxn], cnt; struct Edge {int to, next, w; }edg[maxn << 1]; void add(int u,int v,int w) {edg[++ cnt] = (Edge) { v, head[u], w }, head[u] = cnt; }int mxk[maxn];void dfs(int p,int pre,int mx) {mxk[p] = mx;for(int i = head[p];i;i = edg[i].next) {int to = edg[i].to, w = edg[i].w;if(to == pre) continue;dfs(to, p, max(mx, w));} }vector<int> vc[maxn];/* 以 i 為中心的聯通分量節點 */int fa[maxn];int getfa(int x) {return x == fa[x] ? x : fa[x] = getfa(fa[x]); }void merge(int u,int v) {int s1 = getfa(u), s2 = getfa(v);if(s1 == s2) return ;fa[s1] = s2; }signed main() { // freopen("S.in", "r", stdin); // freopen("S.out", "w", stdout);int i, j;r1(n, Q, S, d);for(i = 1; i <= n; ++ i) r1(a[i]), s.insert(make_pair(a[i], i));for(i = 1; i <= n; ++ i) fa[i] = i;while(1) {for(i = 1; i <= n; ++ i) vc[i].clear();int flag(1);for(i = 1; i <= n; ++ i) {if(getfa(i) != getfa(1)) flag = 0;vc[getfa(i)].push_back(i);}if(flag) break;for(i = 1; i <= n; ++ i) if(vc[i].size()) {int x(0), y(0), w(2e9);for(int v : vc[i]) s.erase(make_pair(a[v], v));for(int v : vc[i]) {auto it = s.lower_bound(make_pair(a[v] + d, 0));int tmp;if(it != s.end()) {tmp = abs(d - abs(a[v] - it->first));if(tmp < w) x = v, y = it->second, w = tmp;}if(it != s.begin()) {-- it;tmp = abs(d - abs(a[v] - it->first));if(tmp < w) x = v, y = it->second, w = tmp;}it = s.lower_bound(make_pair(a[v] - d, 0));if(it != s.end()) {tmp = abs(d - abs(a[v] - it->first));if(tmp < w) x = v, y = it->second, w = tmp;}if(it != s.begin()) {-- it;tmp = abs(d - abs(a[v] - it->first));if(tmp < w) x = v, y = it->second, w = tmp;}}for(int v : vc[i]) s.insert(make_pair(a[v], v));if(getfa(x) != getfa(y)) {add(x, y, w), add(y, x, w); // printf("%d %d %d\n", x, y, w);merge(x, y);}}}dfs(S, 0, 0);while(Q --) {int pos, K;r1(pos, K);if(mxk[pos] <= K) puts("YES");else puts("NO");}return 0; }總結
以上是生活随笔為你收集整理的CF1550F Jumping Around 题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SL1550-ASEMI肖特基二极管SL
- 下一篇: 嵌入式第一堂