洛谷 CF1777E Edge Reverse 题解
要使最大值最小,那么基本可以确定本题是二分了。先二分最终答案,再判断最大值为 \(x\) 可不可行。由于不可能同一条边两个方向都走,所以可以直接把反转边变成无向边,相当于添加了一条原有边的反向边。加边对于本题来说当然是有利无害的,所以我们可以将边权小于等于 mid 的边全部增添它们的反向边。
接下来就要想办法判断是否存在一个点能到达其他点了。因为增加边后图有很多边,同时可能存在一些环,我们难以较快地找出能到达所有点的点。于是考虑缩点,得到一个 DAG 之后我们就很好处理了,只要除了起点的点入度不为 \(0\) 就可以满足要求。
另外还有一点,缩点后建边时不需要去重,因为我们是要找入度为 \(0\) 的点的个数,而入度为 \(0\) 的点不存在指向它的边,所以不去重边是一样的。之前加了去重边就被卡了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<unordered_map>
using namespace std;
const int N=2e5+100;
int n,m,sbt,u[N],v[N],w[N],l,r,mid,t[N],k,rk,rt[N],b[N],bk,scc[N],cnt,d[N];
bool flag[N];
struct node
{
int id,last,val;
}a[N*2],ra[N*2];
void add(int a1,int a2)
{
a[++k].id=a2;
a[k].last=t[a1];
t[a1]=k;
}
void radd(int a1,int a2)
{
ra[++rk].id=a2;
ra[rk].last=rt[a1];
rt[a1]=rk;
}
void dfs1(int x)
{
flag[x]=true;
for(int i=t[x];i;i=a[i].last)
{
if(!flag[a[i].id]) dfs1(a[i].id);
}
b[++bk]=x;
}
void dfs2(int x,int c)
{
scc[x]=c;
for(int i=rt[x];i;i=ra[i].last)
{
if(!scc[ra[i].id]) dfs2(ra[i].id,c);
}
}
void kosaraju()
{
bk=cnt=0;
for(int i=1;i<=n;i++) flag[i]=false,scc[i]=0;
for(int i=1;i<=n;i++)
{
if(!flag[i]) dfs1(i);
}
for(int i=n;i>=1;i--)
{
if(!scc[b[i]]) dfs2(b[i],++cnt);
}
}
bool check(int x)
{
int c0=0;
//unordered_map<int,bool> um[N];
k=rk=0;
for(int i=1;i<=n;i++) t[i]=rt[i]=0;
for(int i=1;i<=m;i++)
{
add(u[i],v[i]),radd(v[i],u[i]);
if(w[i]<=x) add(v[i],u[i]),radd(u[i],v[i]);
}
kosaraju();
for(int i=1;i<=n;i++) d[i]=0;
//for(int i=1;i<=n;i++) printf("%d",scc[i]);
for(int i=1;i<=m;i++)
{
if(scc[u[i]]!=scc[v[i]]/*&&!um[u[i]].count(v[i])*/)
{
//um[u[i]][v[i]]=true;
d[scc[v[i]]]++;
}
if(w[i]<=x)
{
if(scc[u[i]]!=scc[v[i]]/*&&!um[v[i]].count(u[i])*/)
{
//um[v[i]][u[i]]=true;
d[scc[u[i]]]++;
}
}
}
for(int i=1;i<=cnt;i++)
{
if(!d[i]) c0++;
}
return c0<=1;
}
int main()
{
scanf("%d",&sbt);
while(sbt--)
{
l=-1,r=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
r=max(r,w[i]+1);
}
while(l+1<r)
{
mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid;
//printf("%d %d\n",l,r);
}
check(r)?printf("%d\n",r):printf("-1\n");
//cout<<check(30001);
}
return 0;
}

浙公网安备 33010602011771号