1. 程式人生 > >EOJ Monthly 2019.2 E. 中位數 (二分+dfs)

EOJ Monthly 2019.2 E. 中位數 (二分+dfs)

contest mat cli 所有 ace set ram nbsp scanf

題目傳送門

題意:

在一個n個點,m條邊的有向無環圖中,求出所有從1到n

的路徑的中位數的最大值

一條路徑的中位數指的是:一條路徑有 n 個點,

將這 n 個點的權值從小到大排序後,排在位置 n2+1 上的權值。

思路:

看到權值為1~1e9,可以想到用二分答案,然後我們在驗證的時候

可以將小於mid的邊權設為-1,大於為1這樣遍歷一遍序列加起來的值

剛好為0

代碼:

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define
N 1000005 const ll INF=2e9; int n,m; int a[N]; vector<int>v[N]; int dis[N]; int vis[N]; int dfs(int mid,int x) { if(vis[x]) return dis[x]; int tmp=a[x]>=mid?1:-1; vis[x]=1; for(int i=0;i<v[x].size();i++) { int t=v[x][i]; dis[x]=max(dis[x],tmp+dfs(mid,t)); }
return dis[x]; } bool check(int mid) { for(int i=1;i<=n;i++) dis[i]=-INF; memset(vis,0,sizeof(vis)); vis[1]=1; dis[1]=a[1]>=mid?1:-1; return dfs(mid,n)>=0; } int main() { while(~scanf("%d %d",&n,&m)) { for(int i=1;i<=n;i++) scanf("%d
",&a[i]); while(m--) { int x,y; scanf("%d%d",&x,&y); v[y].push_back(x); } ll l=0,r=INF; ll ans=-1; while(l<=r) { ll mid=l+r>>1; if(check(mid)) { l=mid+1; ans=mid; } else r=mid-1; } printf("%lld\n",ans); } return 0; }
View Code

EOJ Monthly 2019.2 E. 中位數 (二分+dfs)