Luogu P3119 [USACO15JAN] Grass Cownoisseur G 题解 [ 蓝 ] [ Tarjan ] [ 分层图 ] [ 枚举 ]
Grass Cownoisseur:还不错的一道 tarjan 题。
观察
首先不难发现同一个 SCC 里的点互相可达,能去其中一个就可以去其他所有点,于是先跑 tarjan 缩点。
然后这张图就成了一个 DAG,要求你最多反转一条边,最大化只经过这一条边一次的一个包含点 \(1\) 所在 SCC 的环的权值。
考虑翻转一条边代表什么,显然翻转一条边就是要走到一些本来去不了的点那里,然后再返回 \(1\)。整体的形态就是从 \(1\) 走到 \(u\),然后走反边,再从 \(v\) 走到 \(1\)。
同时还有一个结论,就是在走过翻转后的边之后,就不能再回到原来走过的点去了。原因很简单,如果还要走回去的话,还不如不翻转这条边呢。并且,如果走到原来的点,就一定没办法再返回 \(1\) 了,因为 DAG 有特殊性质,\(1\) 原来能到的点是一定不能在原图上返回 \(1\) 的。
简而言之就是所有点可以被分为 \(3\) 类,一个是能被 \(1\) 到达的,一个是能到达 \(1\) 的,还有是孤立点的。
枚举
到这里就是好做的了,我们先正向拓扑一遍,求出从 \(1\) 到第一类点的最长链。在反向拓扑一遍,求出第二类点到 \(1\) 的最长链。然后枚举每条边,如果边的两端分别是一类和二类点,就说明可以走这条边的反向边,更新答案即可。
注意可以有不走任何反向边的情况。
时间复杂度 \(O(n+m)\)。
我写的是这种做法。
分层图
分层图也是一样的,把所有点拆成两个点,然后反向边连接两层即可。因为“如果走到原来的点,就一定没办法再返回 \(1\) 了”这个优良性质,所以一定不会让一个点被重复贡献,跑拓扑最长路即可。
时间复杂度 \(O(n+m)\)。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=100005,M=1000005;
int n,m,ans;
int h[N],idx=0;
struct Edge{
int v,ne;
}e[M];
void add(int u,int v)
{
e[++idx]={v,h[u]};
h[u]=idx;
}
int dfn[N],low[N],stk[N],tp,scc[N],sz[N],id,tot,dp[2][N];
bitset<N>instk;
void tarjan(int u)
{
dfn[u]=low[u]=++tot;
stk[++tp]=u;instk[u]=1;
for(int i=h[u];i;i=e[i].ne)
{
int v=e[i].v;
if(dfn[v]==0)
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instk[v])
{
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u])
{
id++;
int x;
do{
x=stk[tp--];
instk[x]=0;
scc[x]=id;
sz[id]++;
}while(x!=u);
}
}
vector<int>g[2][N];
int main()
{
//freopen("sample.in","r",stdin);
//freopen("sample.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
while(m--)
{
int u,v;
cin>>u>>v;
add(u,v);
}
for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i);
for(int u=1;u<=n;u++)
{
int sccu=scc[u];
for(int i=h[u];i;i=e[i].ne)
{
int v=e[i].v;
int sccv=scc[v];
if(sccu!=sccv)
{
g[0][sccu].push_back(sccv);
g[1][sccv].push_back(sccu);
}
}
}
memset(dp,-0x3f,sizeof(dp));
dp[0][scc[1]]=sz[scc[1]];
for(int u=id;u>=1;u--)
{
for(auto v:g[0][u])
{
dp[0][v]=max(dp[0][v],dp[0][u]+sz[v]);
}
}
dp[1][scc[1]]=0;
for(int u=1;u<=id;u++)
{
for(auto v:g[1][u])
{
dp[1][v]=max(dp[1][v],dp[1][u]+sz[v]);
}
}
ans=max(ans,sz[scc[1]]);
for(int u=1;u<=id;u++)
{
for(auto v:g[0][u])
{
ans=max(ans,dp[0][v]+dp[1][u]);
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号