[BZOJ1093]ZJOI2007最大半联通子图|强联通分量|DP

剖析其本质,其实缩点之后的一条链就是一个半联通分量。。那么任务就变成求一个DAG上的最长链及其数量,那么就spfa/拓扑排序/记忆化搜索搞定。。其实是我的OrzCC T3的弱化版233。。

#include<cstdio>
#include<iostream>
#include<memory.h>
#define N 200005
#define clr(a) memset(a,0,sizeof(a))
using namespace std;
struct edge{
  int e,next;
}ed[N*10];
int n,m,p,s,e,i,j,ne=0,scc=0,top=0,a[N],t=0,ans=0,sum=0,dp[N],num[N],belong[N],dfn[N],low[N],in[N],st[N],size[N],ins[N];
void add(int s,int e)
{
  ed[++ne].e=e;ed[ne].next=a[s];
  a[s]=ne;
}
void tarjan(int x)
{
  dfn[x]=low[x]=++t;
  st[++top]=x;ins[x]=1;
  for (int j=a[x];j;j=ed[j].next)
	{
	  if (!dfn[ed[j].e]) tarjan(ed[j].e);
	  if (ins[ed[j].e]) low[x]=min(low[x],low[ed[j].e]);
	}
  if (low[x]==dfn[x])
	{
	  ++scc;
	  while (st[top+1]!=x) belong[st[top--]]=n+scc,ins[st[top+1]]=0,size[n+scc]++; 
	}
}
void dfs(int x,int d)
{
  int to;
  dfn[x]=d;
  dp[x]=size[x];num[x]=1;
  for (int j=a[x];j;j=ed[j].next)
	if(dfn[to=ed[j].e]<x)
	  {
		dfs(to,d);
		if (dp[to]+size[x]>dp[x]) dp[x]=dp[to]+size[x],num[x]=num[to];
		else if (dp[to]+size[x]==dp[x]) num[x]=(num[x]+num[to])%p;
	  } 
}
int main()
{
  freopen("1093.in","r",stdin);
  scanf("%d%d%d",&n,&m,&p);
  for(i=1;i<=m;i++)
	{
	  scanf("%d%d",&s,&e);
	  add(s,e);
	}
  clr(dfn);clr(low);clr(belong);clr(in);clr(size);clr(ins);
  for (i=1;i<=n;i++) if (!dfn[i]) tarjan(i);  
  for (i=1;i<=n;i++)
	for (j=a[i];j;j=ed[j].next)
	  if (belong[i]!=belong[ed[j].e]) add(belong[i],belong[ed[j].e]),in[belong[ed[j].e]]++;
  clr(dp);clr(num);
  t=0;
  for (i=n+1;i<=n+scc;i++)
	if (!in[i])
	  {
		dfs(i,++t);
		if (dp[i]>ans) ans=dp[i],sum=num[i];
		else if (dp[i]==ans) sum=(sum+num[i])%p;
	  }
  printf("%d\n%d\n",ans,sum);
}
#include<cstdio>
#include<iostream>
#include<memory.h>
#define N 200005
#define clr(a) memset(a,0,sizeof(a))
using namespace std;
struct edge{
  int e,next;
}ed[N*10];
int n,m,p,s,e,i,j,ne=0,scc=0,top=0,a[N],t=0,ans=1,sum,dp[N],num[N],belong[N],dfn[N],low[N],in[N],st[N],size[N],ins[N];
void add(int s,int e)
{
  ed[++ne].e=e;ed[ne].next=a[s];
  a[s]=ne;
}
void tarjan(int x)
{
     
  dfn[x]=low[x]=++t;
  st[++top]=x;ins[x]=1;
  for (int j=a[x];j;j=ed[j].next)
    {
      if (!dfn[ed[j].e]) tarjan(ed[j].e);
      if (ins[ed[j].e]) low[x]=min(low[x],low[ed[j].e]);
    }
  if (low[x]==dfn[x])
    {
      ++scc;
      while (st[top+1]!=x) belong[st[top--]]=n+scc,ins[st[top+1]]=0,size[n+scc]++;
    }
}
void dfs(int x,int d)
{
  int to;
  dfn[x]=d;
  dp[x]=size[x];num[x]=1;
  for (int j=a[x];j;j=ed[j].next)
    if(dfn[to=ed[j].e]!=x)
      {
        if (!dfn[to]) dfs(to,x);
        dfn[to]=x;
        if (dp[to]+size[x]>dp[x]) dp[x]=dp[to]+size[x],num[x]=num[to];
        else if (dp[to]+size[x]==dp[x]) num[x]=(num[x]+num[to])%p;
      }
}
int main()
{
  scanf("%d%d%d",&n,&m,&p);
  for(i=1;i<=m;i++)
    {
      scanf("%d%d",&s,&e);
      add(s,e);
    }
  clr(dfn);clr(low);clr(belong);clr(in);clr(size);clr(ins);
  for (i=1;i<=n;i++) if (!dfn[i]) tarjan(i); 
  for (i=1;i<=n;i++)
    for (j=a[i];j;j=ed[j].next)
      if (belong[i]!=belong[ed[j].e]) add(belong[i],belong[ed[j].e]),in[belong[ed[j].e]]++;
  clr(dp);clr(num);
  ans=sum=0;
  for (i=n+1;i<=n+scc;i++)
    if (!in[i])
      {
        dfs(i,1);
        if (dp[i]>ans) ans=dp[i],sum=num[i];
        else if (dp[i]==ans) sum=(sum+num[i])%p;
      }
  printf("%d\n%d\n",ans,sum);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值