【题目描述】
有一个n个点m条边的有向图,xlm可以从1号点出发在图上走,并且最终需要回到1号点。每个点都有一个神犇(包括1号点),每次经过一个没到过的点,xlm都会膜拜那位神犇。xlm希望膜拜尽可能多的神犇。
由于xlm膜拜神犇的欲望非常强烈,所以他可以有一次机会逆着一条有向边的方向走。(需要注意的是,这条边的方向不会改变)
你现在想知道,xlm最多能膜拜多少神犇?
【输入格式】
输入到OrzOrz.in
第一行2个整数n、m,分别表示图的点数和边数。
第2行到底m+1行,每行两个整数u,v,描述一条u到v的有向边。
【输出格式】
输出到OrzOrz.out
一行一个整数表示xlm最多能膜拜多少神犇。
【样例输入】
7 10 1 2 3 1 2 5 2 4 3 7 3 5 3 6 6 5 7 2 4 7
【样例输出】
6
【提示】
【数据范围】
对于25%的数据,保证n<=100,m<=250,
对于43.75%的数据,保证n<=3,000,m<=7,000。
对于100%的数据,保证n,m<=100,000。
【来源】
QBXT春令营精英班第一次测试T2
先tarjan缩一波点
那么图变成了一个DAG
考虑一条边被反转的贡献 是从1到这条边终点最长路+从1到这条边起点最长路-1号点所在scc点数
最长路用spfa跑
时间复杂度O(n*玄学)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int maxn=100000+10;
vector<int>A[maxn];
vector<int>G[maxn];
vector<int>RG[maxn];
int f[maxn],g[maxn];
int s[maxn];
int dfn[maxn],low[maxn];
int ins[maxn];
int ind=0;
int edge=1;
int vis[maxn];
int size[maxn];
int top=0;
int fa[maxn];
queue<int>q;
inline void tarjan(int x){
dfn[x]=low[x]=++ind;
s[++top]=x;
ins[x]=1;
for(int i=0;i<A[x].size();i++){
int u=A[x][i];
if(!dfn[u]){
tarjan(u);
low[x]=min(low[x],low[u]);
}
else if(ins[u])
low[x]=min(low[x],dfn[u]);
}
if(low[x]==dfn[x]){
while(s[top]!=x){
size[x]++;
fa[s[top]]=x;
ins[s[top]]=0;
top--;
}
size[x]++;
ins[x]=0;
fa[x]=x;
top--;
}
}
int main(){
freopen("OrzOrz.in","r",stdin);
freopen("OrzOrz.out","w",stdout);
int n,m;
scanf("%d %d",&n,&m);
int x,y;
for(int i=1;i<=m;i++){
scanf("%d %d",&x,&y);
A[x].push_back(y);
}
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
for(int j=0;j<A[i].size();j++)
if(fa[i]!=fa[A[i][j]]){
G[fa[i]].push_back(fa[A[i][j]]);
RG[fa[A[i][j]]].push_back(fa[i]);;
}
q.push(fa[1]);
memset(f,-127/2,sizeof(f));
memset(vis,0,sizeof(vis));
f[fa[1]]=size[fa[1]];
vis[fa[1]]=1;
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<G[x].size();i++){
int u=G[x][i];
if(f[u]<f[x]+size[u]){
f[u]=f[x]+size[u];
if(!vis[u]){
vis[u]=1;
q.push(u);
}
}
}
vis[x]=0;
}
q.push(fa[1]);
memset(g,-127/2,sizeof(g));
memset(vis,0,sizeof(vis));
g[fa[1]]=size[fa[1]];
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;i<RG[x].size();i++){
int u=RG[x][i];
if(g[u]<g[x]+size[u]){
g[u]=g[x]+size[u];
if(!vis[u]){
vis[u]=1;
q.push(u);
}
}
}
vis[x]=0;
}
int ans=size[fa[1]];
for(int i=1;i<=n;i++){
if(fa[i]!=i)
continue;
for(int j=0;j<G[i].size();j++){
int u=G[i][j];
if(g[i]+f[fa[u]]-size[fa[1]]>ans)
ans=g[i]+f[fa[u]]-size[fa[1]];
}
}
printf("%d\n",ans);
//for(int i=1;i<=n;i++)
// printf("%d\n",g[i]);
return 0;
}