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

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值