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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)

發布時間:2024/9/5 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【題目鏈接】

【思路】:

根據題意可以明顯看出,當所有任務都完成時的時間是最終的結果,也就是說本題要求,求出最小的最大值。

那這樣的話就暗示了將答案二分,進行check。

【check方法】:

如果說當前答案為ans,每個任務設為p[i],所花費的時間是p[i].tim,所有任務p[i].tim的最大值為maxdis

那么則將符合條件p[i].tim>=ans的數量num求出來,這個數量也就是符合條件的路徑的數量(一個任務在u,v之間有一個簡單路徑很容易理解),

然后找到一個所有路徑中他們的公共邊(公共邊就是這個邊在符合條件的p[i]中出現的次數==num的邊)中最大的一個mmax,如果說

maxdis-mmax<=ans那么check返回1,使得上界變成mid-1,理由是如果最長的路減去一個此時最大的公共邊比此時答案ans小,說明ans還可以

繼續減小,即讓最大值變得更小,反之則不能。

【尋找公共邊方法】:

使用樹上差分,對任務進行離線處理,定義cnt[x]是x到x的父親gra[x][0]這條邊經過的次數,在check函數中,符合p[i].tim>ans的就讓cnt[p[i].u] ++, cnt[p[i].v]++, cnt[p[i].lca] -= 2

所有的任務都判斷完成時,進行Dfs更新所有節點的cnt[],當cnt[x]==num && dis[x]-dis[gra[x][0]]>=mmax時更新mmax。進行完Dfs后判斷maxdis-mmax與ans關系即可。

?

#include <bits/stdc++.h> using namespace std;const int maxn = 3e5 + 5; const int maxm = maxn; const int inf = 0x3f3f3f3f; int n, m, mmax, num, ans, maxdis; struct edge{int to, w, next; } ed[maxn<<1]; struct plan{int u, v, lca, tim;plan( int u=0, int v=0, int lca=0, int tim=0 ): u(u),v(v),lca(lca),tim(tim){} } p[maxm]; int head[maxn], tot, cnt[maxn]; int gra[maxn][25], dep[maxn], dis[maxn], maxdep; inline int read(){int k=0, f=1; char ch=getchar();while( ch>'9'|| ch<'0' ){ if( ch=='-' ) f = -1; ch = getchar(); }while( ch<='9' && ch>='0' ){ k = k*10+ch-'0'; ch = getchar(); }return k*f; }inline void init(){memset( head ,-1 ,sizeof(head) );memset( gra, 0, sizeof(gra) );maxdep = log(n)/log(2);tot = 1; }inline void add( int u, int v, int w ){ed[++tot].to = v;ed[tot].w = w;ed[tot].next = head[u];head[u] = tot; }inline void dfs_lca( int x ){ //初始化與LCA相關的數據for( int i=1; i<=maxdep; i++ ){gra[x][i] = gra[gra[x][i-1]][i-1];if( !gra[x][i] ) break;}for( int i=head[x]; ~i; i=ed[i].next ){int y = ed[i].to;if( y==gra[x][0] ) continue;dep[y] = dep[x]+1;dis[y] = dis[x]+ed[i].w;gra[y][0] = x;dfs_lca(y);} }inline void dfs_diff( int x ){for( int i=head[x]; ~i; i=ed[i].next ){int y = ed[i].to;if(y==gra[x][0]) continue;dfs_diff(y);cnt[x] += cnt[y];}if( cnt[x]==num && mmax<dis[x]-dis[gra[x][0]] ) //尋找最大的公共邊mmax = dis[x]-dis[gra[x][0]]; }inline void swap( int &a, int &b ){int t = a;a = b;b = t; }inline int LCA( int x, int y ){if(dep[x]>dep[y]) swap(x, y);for( int i=maxdep; ~i; i-- )if( gra[y][i]==x ) return x; //避免卡常,能return就returnelse if( dep[gra[y][i]]>=dep[x] ) y = gra[y][i];if( x==y ) return x; //避免卡常for( int i=maxdep; ~i; i-- )if( gra[x][i]!=gra[y][i] ){x = gra[x][i];y = gra[y][i];}if( x!=y ) x = gra[x][0];return x; }inline int max( int a, int b ){return a>b ? a:b; }inline bool check( int x ){mmax = num = 0; //每次check都將mmax, num, cnt初始化為0memset( cnt ,0, sizeof(cnt) );for( int i=1; i<=m; i++ ){if( p[i].tim<=x ) continue;num ++;cnt[p[i].u] ++;cnt[p[i].v] ++;cnt[p[i].lca] -= 2;}dfs_diff(1); //更新每個結點的cntreturn maxdis-mmax<=x; }int main(){n = read(); m = read(); //讀取方式使用快讀,此題卡常數卡的很厲害 init();int maxe = -inf;for( int i=1; i<n; i++ ){int u, v, w;u = read(); v = read(); w = read();add(u, v, w);add(v, u, w);maxe = max( maxe, w );}dep[1] = 1;dis[1] = 0;dfs_lca(1);maxdis = -inf;for( int i=1; i<=m ;i++ ){int u, v;u = read(); v = read();int lca = LCA(u, v);p[i] = plan( u, v, lca, dis[u]+dis[v]-(dis[lca]<<1) ); //儲存,后續進行離線處理maxdis = max( maxdis, p[i].tim ); //獲得一條邊都不是蟲洞的最大值 }int l = maxdis-maxe, r = maxdis; //這里要優化下界l,不然會超時while( l<=r ){int mid = (l+r)>>1;if( check(mid) ){ans = mid;r = mid-1;}else l = mid+1;}printf("%d\n", ans);return 0; }

?

?

?

?

轉載于:https://www.cnblogs.com/WAautomaton/p/11181217.html

總結

以上是生活随笔為你收集整理的洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)的全部內容,希望文章能夠幫你解決所遇到的問題。

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