【JZOJ 5452】【NOIP2017提高A组冲刺11.5】轰炸

时间:2022-12-17 14:22:16

Description

战狂也在玩《魔方王国》。他只会征兵而不会建城市,因此他决定对小奇的城市进行轰炸。
小奇有n 座城市,城市之间建立了m 条有向的地下通道。战狂会发起若干轮轰炸,每轮可以轰炸任意多个城市。
每座城市里都有战狂部署的间谍,在城市遭遇轰炸时,它们会通过地下通道撤离至其它城市。非常不幸的是,在地道里无法得知其它城市是否被轰炸,如果存在两个不同的城市i,j,它们在同一轮被轰炸,并且可以通过地道从城市i 到达城市j,那么城市i 的间谍可能因为撤离到城市j 而被炸死。为了避免这一情况,战狂不会在同一轮轰炸城市i 和城市j。
你需要求出战狂最少需要多少轮可以对每座城市都进行至少一次轰炸。

Solution

人工栈模板

Code

#include <cstdio>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
const int N=1000500;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
int a[N];
int B[4*N][2],A[N],B0;
int dfn[N],low[N],dfn0,g[N];
int za1[N];
int za[N][2],za0;
bool z1[N],z[N];
int b[N],f[N];
void link(int q,int w){B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w;}
void tarjan(int q)
{
int i;
for(za[za0=1][0]=q;za0;)
{
i=za[za0][1],q=za[za0][0];
if(!i)i=A[q],low[q]=dfn[q]=++dfn0,za1[++za1[0]]=q,z[q]=z1[q]=1;
else low[q]=min(low[q],low[B[i][1]]),i=B[i][0];
for(;i&&z[B[i][1]];i=B[i][0])if(z1[B[i][1]])low[q]=min(low[q],low[B[i][1]]);
za[za0][1]=i;
if(i)za[++za0][0]=B[i][1],za[za0][1]=0;
else
{
if(low[q]==dfn[q])
for(;za1[za1[0]+1]!=q;za1[0]--)g[za1[za1[0]]]=q,z1[za1[za1[0]]]=0,za1[za1[0]+1]=0;
za0--;
}
}
}
void dfs(int q)
{
int i;
for(za[za0=1][0]=q;za0;)
{
i=za[za0][1],q=za[za0][0];
if(!i)i=A[q],z[q]=0;
else f[q]=max(f[q],f[g[B[i][1]]]),i=B[i][0];
for(;i&&!z[g[B[i][1]]];i=B[i][0])f[q]=max(f[q],f[g[B[i][1]]]);
za[za0][1]=i;
if(i)za[++za0][0]=g[B[i][1]],za[za0][1]=0;
else f[q]+=b[q],za0--;
}
}
int main()
{
freopen("bomb.in","r",stdin);
freopen("bomb.out","w",stdout);
int q,w;
read(n),read(m);
fo(i,1,m)read(q),read(w),link(q,w);
fo(i,1,n)if(!z[i])tarjan(i);
fo(i,1,n)
{
b[g[i]]++;
if(g[i]!=i)
{
efo(j,i)link(g[i],B[j][1]);
}
}
fo(i,1,n)if(z[i])dfs(i);
ans=0;
fo(i,1,n)ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}