[ZJOI2007]最大半连通子图

Posted lizehon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ZJOI2007]最大半连通子图相关的知识,希望对你有一定的参考价值。

Luogu2272

图论基础

//经典图论题 二周目 2018.11.6
#include<bits/stdc++.h>
using namespace std;

inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}

typedef long long LL;
inline LL read(){
    register LL x=0,f=1;register char c=getchar();
    while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
    while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
    return f*x;
}

const int MAXN=100005;
const int MAXM=1000005;

struct Edge{
    int u,v,next;
}e[MAXM];
int first[MAXN],Ecnt;
inline void Add_edge(int u,int v){
    e[++Ecnt]=(Edge){u,v,first[u]};
    first[u]=Ecnt;
}

int low[MAXN],dfn[MAXN],ctg[MAXN],size[MAXN],st[MAXN],f[MAXN],g[MAXN],in[MAXN];
int n,m,mod,idx,ctgn,top,ans1,ans2;

typedef pair<int,int> pii;
set <pii> S;
queue <int> q;

inline void tarjan(int u){
    low[u]=dfn[u]=++idx;
    st[++top]=u;
    for(int i=first[u];i;i=e[i].next){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[u]=Min(low[u],low[v]);
        }
        else if(!ctg[v]) low[u]=Min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        ctg[u]=++ctgn;
        size[ctgn]++;
        while(st[top]!=u){
            ctg[st[top]]=ctgn;
            size[ctgn]++;
            top--;
        }
        top--;
    }
}

int main(){
    n=read(),m=read(),mod=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        Add_edge(x,y);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=m;i++){
        int u=e[i].u,v=e[i].v;
        if(ctg[u]!=ctg[v])
            S.insert(pii(ctg[u],ctg[v]));//用set判重
    }
    Ecnt=0;
    memset(first,0,sizeof first);//重建图时清空first!!!!!
    for(set<pii>::iterator it=S.begin();it!=S.end();it++){
        Add_edge(it->first,it->second);
        in[it->second]++;
    }
    for(int i=1;i<=ctgn;i++){
        if(!in[i]){
            q.push(i);
            f[i]=size[i];//初始时放入长度
            g[i]=1;
        }
    }
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=first[u];i;i=e[i].next){
            int v=e[i].v;
            if(--in[v]<=0) q.push(v);
            if(f[u]+size[v]>f[v]){
                f[v]=f[u]+size[v];
                g[v]=0;
            }
            if(f[u]+size[v]==f[v])
                (g[v]+=g[u])%=mod;
        }
    }
    for(int i=1;i<=ctgn;i++){
        if(f[i]>f[ans1])
            ans1=i,ans2=0;
        if(f[i]==f[ans1])
            (ans2+=g[i])%=mod;
    }
    printf("%d\n%d\n",f[ans1],ans2);
}

以上是关于[ZJOI2007]最大半连通子图的主要内容,如果未能解决你的问题,请参考以下文章

[ZJOI2007]最大半连通子图

ZJOI2007最大半联通子图

bzoj 1093: [ZJOI2007]最大半连通子图

tarjan 拓扑排序 dpbzoj1093: [ZJOI2007]最大半连通子图

[ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)

bzoj1093: [ZJOI2007]最大半连通子图