bzoj 3887: Grass Cownoisseur Tarjan+Topusort
题目:
给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1)
题解:
首先考虑简单一些的问题
如果没有逆向的机会,那么\(ans\)即为\(1\)所在的强连通分量的大小。
但是现在有一个逆向的机会
如果我们将缩点后的\(DAG\)搞出来的话就可以发现:
一定是从\(1\)的连通块出发走到别的地方然后通过走逆向边返回一个可以到达\(1\)的路径上。
那么我们可以预处理每个点到根的最大\(siz\)之和根到每个点的路上的最大\(siz\)之和。
然后枚举每条边进行\(O(1)\)判断即可.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 100010;
struct Edge{
int to,next;
}G[maxn];
int head[maxn],cnt;
void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
int dfn[maxn],low[maxn],dfs_clock;
int sta[maxn],top,belong[maxn];
int scc_cnt,siz[maxn];
#define v G[i].to
void dfs(int u){
dfn[u] = low[u] = ++ dfs_clock;
sta[++top] = u;
for(rg i = head[u];i;i=G[i].next){
if(!dfn[v]){
dfs(v);
low[u] = min(low[u],low[v]);
}else if(!belong[v]) low[u] = min(low[u],dfn[v]);
}
if(dfn[u] == low[u]){
++ scc_cnt;
while(1){
int x = sta[top--];
belong[x] = scc_cnt;
siz[scc_cnt] ++ ;
if(x == u) break;
}
}
}
#undef v
struct Topu{
struct Edge{
int to,next;
}G[maxn];
int head[maxn],cnt,deg[maxn];
void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
++ deg[v];
}
#define v G[i].to
int q[maxn],l,r,f[maxn];
void bfs(){
memset(f,-0x3f,sizeof f);
f[belong[1]] = siz[belong[1]];l = 0;r = -1;
rep(i,1,scc_cnt){
if(deg[i] == 0) q[++r] = i;
}
while(l <= r){
int u = q[l++];
for(rg i = head[u];i;i=G[i].next){
f[v] = max(f[v],f[u] + siz[v]);
if(-- deg[v] == 0) q[++r] = v;
}
}return ;
}
#undef v
}a,b;
struct Node{
int u,v;
}e[maxn];
int main(){
int n,m;read(n);read(m);
int u,v;
rep(i,1,m){
read(u);read(v);
e[i].u = u;e[i].v = v;
add(u,v);
}
rep(i,1,n) if(!dfn[i]) dfs(i);
rep(i,1,m){
if(belong[e[i].u] == belong[e[i].v]) continue;
a.add(belong[e[i].u],belong[e[i].v]);
b.add(belong[e[i].v],belong[e[i].u]);
}a.bfs();b.bfs();
int ans = siz[belong[1]] << 1;
rep(i,1,m){
if(belong[e[i].u] == belong[e[i].v]) continue;
ans = max(ans,a.f[belong[e[i].v]] + b.f[belong[e[i].u]]);
}
printf("%d\n",ans - siz[belong[1]]);
return 0;
}
人就像命运下的蝼蚁,谁也无法操控自己的人生.