Description
战狂也在玩《魔方王国》。他只会征兵而不会建城市,因此他决定对小奇的城市进行轰炸。
小奇有n 座城市,城市之间建立了m 条有向的地下通道。战狂会发起若干轮轰炸,每轮可以轰炸任意多个城市。
每座城市里都有战狂部署的间谍,在城市遭遇轰炸时,它们会通过地下通道撤离至其它城市。非常不幸的是,在地道里无法得知其它城市是否被轰炸,如果存在两个不同的城市i,j,它们在同一轮被轰炸,并且可以通过地道从城市i 到达城市j,那么城市i 的间谍可能因为撤离到城市j 而被炸死。为了避免这一情况,战狂不会在同一轮轰炸城市i 和城市j。
你需要求出战狂最少需要多少轮可以对每座城市都进行至少一次轰炸。
Input
第一行两个整数n,m。接下来m 行每行两个整数a,b 表示一条从a 连向b的单向边。
Output
输出一行仅一个整数表示答案。
Sample Input
5 4
1 2
2 3
3 1
4 5
Sample Output
3
Data Constraint
对于20%的数据,n,m<=10。
对于40%的数据,n,m<=1000。
对于另外30%的数据,保证无环。
100%的数据,n,m<=1000000。
题解
首先,不要误解题意:“并且可以通过地道从城市i 到达城市j”,这里是到达,而不是直接有边相连。
位于同一条链的点是不能同时炸的,位于同一个强连通分量的也不能同时炸。
所以做法很简单,
先用tarjan缩环,然后再跑一遍最长链。
由于这里的n比较大,所以递归版的tarjan会爆栈,要写人工栈。
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 1000003
using namespace std;
char ch;
void read(int& n)
{
n=0;
for(ch=getchar();ch<'0' || ch>'9';ch=getchar());
for(;'0'<=ch && ch<='9';n=(n<<3)+(n<<1)+ch-48,ch=getchar());
}
int n,m,x,y,lb[N][2],fa[N];
int nxt[N*2],to[N*2],b[N],tot,v[N],p[N*2];
int low[N],z[N],top,dfn[N],cnt,now,f[N],ans;
bool bz[N],w[N],pd;
int nxt1[N*2],to1[N*2],b1[N],tot1,f1,f2;
int g[N],dis[N],d[N],l,r;
void ins(int x,int y)
{
nxt[++tot]=b[x];
to[tot]=y;
b[x]=tot;
}
void ins1(int x,int y)
{
nxt1[++tot1]=b1[x];
to1[tot1]=y;
b1[x]=tot1;
g[y]++;
}
/*void tarjan(int x)
{
z[++top]=x;
bz[x]=w[x]=0;
dfn[x]=low[x]=++now;
for(int i=b[x];i;i=nxt[i])
if(bz[to[i]])
{
tarjan(to[i]);
low[x]=min(low[x],low[to[i]]);
}else if(!w[to[i]])
low[x]=min(low[x],dfn[to[i]]);
if(low[x]==dfn[x])
{
cnt++;
z[top+1]=-1;
while(z[top+1]!=x)
{
f[z[top]]=cnt;
v[cnt]++;
w[z[top]]=1;
top--;
}
ans=max(ans,v[cnt]);
}
}*/
void tarjan(int x)
{
d[r=1]=x;
while(r)
{
x=d[r];
if(dfn[x]==0)
{
z[++top]=x;
bz[x]=w[x]=0;
dfn[x]=low[x]=++now;
}
if(b[x])
{
int i=b[x];
if(p[i]==0)
{
low[x]=min(low[x],low[to[i]]);
} else
if(bz[to[i]])
{
if(p[i])
{
d[++r]=to[i];
p[i]=0;
continue;
}
}else if(!w[to[i]])
low[x]=min(low[x],dfn[to[i]]);
b[x]=nxt[i];
}
else
{
if(low[x]==dfn[x])
{
cnt++;
z[top+1]=-1;
while(z[top+1]!=x)
{
f[z[top]]=cnt;
v[cnt]++;
w[z[top]]=1;
top--;
}
ans=max(ans,v[cnt]);
}
r--;
}
}
}
int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);}
int main()
{
freopen("bomb.in","r",stdin);
freopen("bomb.out","w",stdout);
read(n);read(m);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
read(x),read(y),ins(x,y),lb[i][0]=x,lb[i][1]=y;
top=now=0;
memset(bz,1,sizeof(bz));
memset(w,1,sizeof(w));
memset(p,1,sizeof(p));
for(int i=1;i<=n;i++)
if(bz[i])tarjan(i);
for(int i=1;i<=m;i++)
if(f[lb[i][0]]!=f[lb[i][1]])ins1(f[lb[i][0]],f[lb[i][1]]);
l=r=0;
for(int i=1;i<=cnt;i++)
if(g[i]==0)d[++r]=i;
while(l<r)
{
x=d[++l];
ans=max(ans,dis[x]+v[x]);
for(int i=b1[x];i;i=nxt1[i])
{
dis[to1[i]]=max(dis[to1[i]],dis[x]+v[x]);
g[to1[i]]--;
if(g[to1[i]]==0)d[++r]=to1[i];
}
}
printf("%d",ans);
return 0;
}