bzoj 1093 [ZJOI2007]最大半连通子图——缩点+拓扑

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1093

缩点+拓扑,更新长度的时候维护方案数。

结果没想到处理缩点后的重边,这样的话方案数会算多。

学习人家处理重边的方法好好。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5,M=1e6+5;
int n,m,hd[N],rd[N],cd[N],mod,dp[N],f[N],ans,prn,lst[N];
int dfn[N],low[N],tim,cnt,col[N],sta[N],top,h,t,siz[N];
bool ins[N];
struct Ed{
    int nxt,fr,to;
    Ed(int n=0,int f=0,int t=0):nxt(n),fr(f),to(t) {}
}ed[M];
int rdn()
{
    int ret=0;char ch=getchar();
    while(ch>'9'||ch<'0')ch=getchar();
    while(ch>='0'&&ch<='9')(ret*=10)+=ch-'0',ch=getchar();
    return ret;
}
void tarjan(int cr)
{
    dfn[cr]=low[cr]=++tim;
    ins[cr]=1;sta[++top]=cr;
    for(int i=hd[cr],v;i;i=ed[i].nxt)
        if(!dfn[v=ed[i].to])
            tarjan(v),low[cr]=min(low[cr],low[v]);
        else if(ins[v])low[cr]=min(low[cr],dfn[v]);
    if(dfn[cr]==low[cr])
    {
        cnt++;
        while(sta[top]!=cr)
        {
            int k=sta[top--];col[k]=cnt;ins[k]=0;siz[cnt]++;
        }
        top--;col[cr]=cnt;ins[cr]=0;siz[cnt]++;
    }
}
int main()
{
    n=rdn();m=rdn();mod=rdn();
    int x,y;
    for(int i=1;i<=m;i++)
    {
        x=rdn();y=rdn();
        ed[i]=Ed(hd[x],x,y);hd[x]=i;
    }
    for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
    memset(hd,0,sizeof hd);
    for(int i=1,u,v;i<=m;i++)
        if((u=col[ed[i].fr])!=(v=col[ed[i].to]))
            ed[i]=Ed(hd[u],u,v),hd[u]=i,rd[v]++,cd[u]++;
    h=1;t=0;
    for(int i=1;i<=n;i++)
        if(!rd[i])dp[i]=siz[i],f[i]=1,sta[++t]=i;
    while(h<=t)
    {
        int k=sta[h++];
        for(int i=hd[k],v;i;i=ed[i].nxt)
        {
            rd[v=ed[i].to]--;if(!rd[v])sta[++t]=v;
            if(lst[v]==k)continue;//会把k的出边全走完,所以不会对v先x再y再x地更新 
            if(dp[k]+siz[v]>dp[v])dp[v]=dp[k]+siz[v],f[v]=f[k];
            else if(dp[k]+siz[v]==dp[v])(f[v]+=f[k])%=mod;
            lst[v]=k;
        }
    }
    for(int i=1;i<=n;i++)if(!cd[i])
        if(dp[i]>ans)ans=dp[i],prn=f[i];
        else if(dp[i]==ans)(prn+=f[i])%=mod;
    printf("%d\n%d\n",ans,prn);
    return 0;
}

 

posted on 2018-07-27 10:49  Narh  阅读(186)  评论(0编辑  收藏  举报

导航