日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CF1550F Jumping Around 题解

發布時間:2024/3/26 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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||minvI,uU/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 题解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。