zoukankan      html  css  js  c++  java
  • 【题解】[ZJOI2007]最大半连通子图

    [ZJOI2007]最大半连通子图

    ( ext{Solution:})

    首先考虑何时满足题目中所说的最大半连通子图。

    先把强连通分量缩起来应该是毋庸置疑的一步了。考虑如何从一个强连通分量来拓展到半连通分量。

    推论1:如果一张缩完点的图是半连通图,那么它的拓扑序一定唯一。

    (Proof:) 假定拓扑序不唯一,也就是在 (bfs) 的过程中,队列同时存在了两个点,那么这两个点必然是无法相互到达的。证毕。

    那么,有了这么一个推论,我们就可以考虑如何解题了:先考虑如何计算最大的节点数。我们缩完点之后令强连通分量的 (siz) 为其连通块大小,问题就转化为了有向图求最长链了。

    那么方案数咋求?考虑设 (f_i,g_i) 分别表示到点 (i) 的最大节点数和方案数。如果更新了 (f) 就把 (g) 置为 (0,) 否则直接累加。比当前 (f) 小的就可以跳过了。

    注意边的去重。可以去枚举原图每次清空数组做到无 $log $ 判重,但是笔者比较懒直接上 map 了。

    注意,计算 (siz) 不能取模,更新 (g) 的时候要取模。

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=4e5+10;
    const int M=4e6+10;
    struct E{int nxt,to;}e[M],edge[M];
    int head[N],Head[N],tot,tto,mod;
    map<int,map<int,int> >mp;
    inline int read(){
    	char ch=getchar();int nn=0,ssss=1;
    	while(ch<'0'||ch>'9'){if(ch=='-')ssss*=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){nn=nn*10+(ch-'0');ch=getchar();}
    	return nn*ssss;
    }
    inline int Add(int x,int y){return (x+y+mod)%mod;}
    inline int Mul(int x,int y){return 1ll*x*y%mod;}
    inline void link(int x,int y,int w=0){
    	if(w){
    		edge[++tto]=(E){Head[x],y};
    		Head[x]=tto;
    		return;
    	}
    	e[++tot]=(E){head[x],y};
    	head[x]=tot;
    }
    int dfn[N],low[N],st[N],top,inst[N],dfstime;
    int c[N],scc,siz[N],in[N],n,m;
    inline int Max(int x,int y){return x>y?x:y;}
    inline int Min(int x,int y){return x<y?x:y;}
    void tarjan(int x){
    	low[x]=dfn[x]=++dfstime;
    	inst[x]=1;st[++top]=x;
    	for(int i=head[x];i;i=e[i].nxt){
    		int j=e[i].to;
    		if(!dfn[j]){
    			tarjan(j);
    			low[x]=Min(low[x],low[j]);
    		}
    		else if(inst[j])low[x]=Min(low[x],dfn[j]);
    	}
    	if(dfn[x]==low[x]){
    		int y=-1;
    		++scc;
    		while(y=st[top--]){
    			siz[scc]++;
    			c[y]=scc;
    			inst[y]=0;
    			if(x==y)break;
    		}
    	}
    }
    struct Rem{int u,v;}rem[M];
    int f[N],g[N];
    void BFS(){
    	queue<int>q;
    	for(int i=1;i<=scc;++i)if(!in[i])q.push(i);
    	for(int i=1;i<=scc;++i)if(!in[i])f[i]=siz[i],g[i]=1;
    	while(!q.empty()){
    		int x=q.front();
    		q.pop();
    		for(int i=Head[x];i;i=edge[i].nxt){
    			int j=edge[i].to;
    			in[j]--;
    			if(!in[j])q.push(j);
    			int v=f[x]+siz[j];
    			if(v<f[j])continue;
    			if(v>f[j]){
    				f[j]=v;
    				g[j]=g[x];
    				continue;
    			}
    			if(v==f[j]){
    				g[j]+=g[x];
    				g[j]%=mod;
    				continue;
    			}
    		}
    	}
    }
    void solve(){
    	int mx=-1;
    	for(int i=1;i<=scc;++i)mx=Max(mx,f[i]);
    	printf("%lld
    ",mx);
    	int res=0;
    	for(int i=1;i<=scc;++i)if(f[i]==mx)res+=g[i],res%=mod;
    	printf("%lld
    ",res);
    }
    signed main(){
    	freopen("semi5.in","r",stdin);
    	n=read();m=read();mod=read();
    	for(int i=1;i<=m;++i){
    		int x=read(),y=read();
    		link(x,y);
    		rem[i]=(Rem){x,y};
    	}
    	for(int i=1;i<=n;++i)if(!dfn[i])top=0,tarjan(i);
    	for(int i=1;i<=m;++i){
    		int u=c[rem[i].u];
    		int v=c[rem[i].v];
    		if(u==v)continue;
    		if(mp[u][v])continue;
    		in[v]++;
    		mp[u][v]=1;
    		link(u,v,1);
    	}
    	BFS();
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    django之session cookie
    自定义分页器
    Django与AJAX
    django之Models里常用小参数choices
    django之跨表查询及添加记录
    django之数据库表的单表查询
    ACM-ICPC 2018 徐州赛区网络预赛 B BE, GE or NE(博弈,记忆化搜索)
    ACM-ICPC 2018 徐州赛区网络预赛 A Hard to prepare
    hdu6365 2018 Multi-University Training Contest 6 1004 Shoot Game
    hdu6444 2018中国大学生程序设计竞赛
  • 原文地址:https://www.cnblogs.com/h-lka/p/15334077.html
Copyright © 2011-2022 走看看