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;
}

posted @ 2017-06-13 15:12  Sky_miner  阅读(211)  评论(0编辑  收藏  举报