题目
有一天,玛莎在公园里散步,在一棵树下发现了一张图表……很惊讶?你认为这个问题会有一些合乎逻辑和合理的故事吗?没门!那么,问题…
Masha 有一个有向图,其中第 i 个顶点包含一些正整数 ai。最初,玛莎可以将硬币放在某个顶点。在一次操作中,她可以将放置在某个顶点 u 中的硬币移动到任何其他顶点 v,从而在图中存在有向边 u→v。每次将硬币放在某个顶点 i 时,玛莎都会在她的笔记本上写下一个整数 ai(特别是,当玛莎最初将硬币放在某个顶点时,她会在笔记本上写下这个顶点处的一个整数)。 Masha 想要精确地进行 k-1 次操作,使得她笔记本上写的最大数字尽可能小。
输入
第一行包含三个整数 n、m 和 k (1≤n≤2⋅105, 0≤m≤2⋅105, 1≤k≤1018)——图中顶点和边的数量,以及操作次数玛莎应该做的。
第二行包含 n 个整数 ai (1≤ai≤109) — 写在图顶点中的数字。
以下 m 行中的每一行都包含两个整数 u 和 v (1≤u≠v≤n)——这意味着图中存在一条边 u→v。
保证图不包含循环和多边。
输出
打印一个整数——玛莎在最佳硬币运动期间在她的笔记本上写的最大数字的最小值。
如果 Masha 无法执行 k-1 操作,则打印 -1。
题解思路
最小化最大值,先往二分上思考,二分出能写的最大值,再使用小于等于最大值的点来建图,再利用拓扑排序来处理最长链以及环的问题。
如果有环那么这个情况必然可以,如果没有环就检查最长链是否大于K。
ygg的代码是用拓扑排序解决的。
参考ygg
pzr佬就用的别的办法,分出判环以及dp最长链的过程。
这里对不联通单边的图判环使用了一个stack来解决判环问题,以前从来没碰到过。
dp过程比较普通就不拓展了。
参考pzr
AC代码
/*从你的全世界路过.*/
#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define int long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 201000 ;
vector <int> head[N] ;
int a[N] ;
int vis[N] ;
int instack[N] ;
int dp[N] ;
long long mid ;
int falg = 0 ;
void dfs(int x )
{
for (int i = 0 ; i < head[x].size() ; i++ )
{
int sk = head[x][i] ;
if ( a[sk] <= mid )
{
if (instack[sk])
{
falg = 1 ;
return ;
}
if ( vis[sk] )
continue;
instack[sk] = 1 ;
vis[sk] = 1 ;
dfs(sk) ;
instack[sk] = 0 ;
}
}
}
void dfs2(int x )
{
dp[x] = 1 ;
for (int i = 0 ; i < head[x].size() ; i++ )
{
int sk = head[x][i] ;
if ( a[sk] <= mid )
{
if ( !dp[sk] )
dfs2(sk) ;
dp[x] = max(dp[sk]+1,dp[x]) ;
}
}
}
void solve()
{
long long n , m , k ;
cin >> n >> m >> k ;
for (int i = 1 ; i <= n ; i++ )
cin >> a[i] ;
for (int i = 1 ; i <= m ; i++ )
{
int t3 , t4 ;
cin >> t3 >> t4 ;
head[t3].push_back(t4) ;
}
long long t1 = 1 , t2 = 1e9 + 10 ;
while ( t1 < t2 )
{
memset(vis,0,sizeof(vis)) ;
memset(dp,0,sizeof(dp)) ;
memset(instack,0,sizeof(instack)) ;
mid = t1 + t2 >> 1 ;
falg = 0 ;
for (int i = 1 ; i <= n ; i++ )
if ( a[i] <= mid && !vis[i] )
instack[i] = 1 ,vis[i] = 1 ,dfs(i) , instack[i] = 0 ;
if ( falg )
{
t2 = mid ;
continue ;
}
for (int i = 1 ; i <= n ; i++ )
if ( a[i] <= mid && !dp[i])
dfs2(i) ;
int st = 0 ;
for (int i = 1 ; i <= n ; i++ )
if ( a[i] <= mid )
st = max(st,dp[i]) ;
if ( st >= k )
t2 = mid ;
else
t1 = mid + 1 ;
}
if ( t2 > 1e9 )
cout << "-1\n" ;
else
cout << t2 << "\n" ;
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
solve() ;
return 0 ;
}