题意:
一张由 n 个点,m 条边构成的有向无环图。每个点有点权 Ai。QQ 小方想知道所有起点为 1 ,终点为 n 的路径中最大的中位数是多少。
一条路径的中位数指的是:一条路径有 n 个点,将这 n 个点的权值从小到大排序后,排在位置 ⌊n2⌋+1 上的权值。
思路(官方题解):
考虑二分答案,我们需要验证路径最大的中位数是否 ≥mid 。
我们把所有的点权做 −1/1 变换,即 ≥mid 的点权变为 1 ,否则变为 −1 。
根据题面路径中位数的定义,我们可以发现,如果这条路径的中位数 ≥mid ,那么做了 −1/1 变换以后,这条路径上的点权和 ≥0 。
而我们现在需要知道的问题是路径最大的中位数是否 ≥mid ,也就是说,最大的路径点权是否 ≥0 。
跑一遍最长路就好了。而对于 DAG ,最长路只要 dp 一下,复杂度是保证 O(m) 。
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<cmath> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 1e6+100; const int maxm = 1e6+100; const int inf = 0x3f3f3f3f; int a[maxn]; int b[maxn]; vector<int>v[maxn]; int dp[maxn]; int n,m; int c(int x, int mid){ return a[x]>=mid?1:-1; } void dpp(int x, int va,int mid){ //printf("%d %d %d ",x,va,mid); if(va<=dp[x])return; dp[x] = max(dp[x],va); //if(x==n)return; for(int i = 0; i < (int)v[x].size(); i++){ dpp(v[x][i], va+c(v[x][i],mid),mid); } return; } bool ck(int x){ //x = b[x]; for(int i = 1; i <= n; i++)dp[i]=-0x3f3f3f3f; dpp(1,c(1,x),x); if(dp[n]>=0)return true; return false; } int main(){ scanf("%d %d",&n,&m); for(int i =1 ; i <= n; i++){ scanf("%d", &a[i]); } for(int i = 1; i <= m; i++){ int x, y; scanf("%d %d", &x, &y); v[x].pb(y); } //printf("%d",ck(5)); int l = 0, r = 1e9; int ans=-1; while(l<=r){ int mid = (r+l)>>1; //printf("%d %d %d ",l,r,mid); if(ck(mid)){ l = mid+1; ans=mid; } else r = mid-1; } printf("%d", ans); return 0; }