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

Posted zhgyki

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EOJ Monthly 2019.2 E. 中位数 (二分+dfs)相关的知识,希望对你有一定的参考价值。

题目传送门

题意:

在一个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
",ans);
    }

    return 0;
}
View Code

 

以上是关于EOJ Monthly 2019.2 E. 中位数 (二分+dfs)的主要内容,如果未能解决你的问题,请参考以下文章

EOJ Monthly 2019.2

EOJ Monthly 2019.2 (based on February Selection) D.进制转换

EOJ Monthly 2020.7 Sponsored by TuSimple E.因数串 数学/ 构造

EOJ Monthly 2019.11 E. 数学题(莫比乌斯反演+杜教筛+拉格朗日插值)

EOJ Monthly 2018.2 (Good bye 2017)

EOJ Monthly 2018.2