Tarjan水题系列(5):最大半连通子图 [ZJOI2007 luogu P2272]

题目

大意

缩点后转为求最长链的长度和最长链的个数

思路:

看懂题就会做系列 长度和个数都可以拓扑排序后DP求得 毕竟是2007年的题

代码:

如下

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <memory.h>
 4 #define r(x) x=read()
 5 #define MAXX 100005
 6 #define MIN(a,b) (a<b?a:b)
 7 #define MAX(a,b) (a>b?a:b)
 8 #define re register
 9 using namespace std;
10 typedef long long ll;
11 int read()
12 {
13   char ch=0;int w=0;
14   while(ch<'0'||ch>'9'){ch=getchar();}
15   while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
16   return w;
17 }
18 int low[MAXX],dfn[MAXX],k,id[MAXX],num,top,sta[MAXX],du[MAXX];
19 int h2[MAXX],h[MAXX],u,to,cnt,book[MAXX],heap,sta2[MAXX];
20 int X,dp[MAXX],ans,w[MAXX],ans2[MAXX];
21 int n,m;
22 struct edge{int to,nex;}e[MAXX<<4],e2[MAXX<<4];
23 void add(int u,int to,int x)
24 {
25   cnt++;
26   if(x==1) {e2[cnt]=(edge){to,h2[u]};h2[u]=cnt;}
27   if(x==2) {e[cnt]=(edge){to,h[u]};h[u]=cnt;}
28 }
29 void tarjan(int now)
30 {
31   low[now]=dfn[now]=++k;
32   sta[++top]=now;
33   for(int i=h2[now];i;i=e2[i].nex)
34   {
35     if(!dfn[e2[i].to])
36       tarjan(e2[i].to),low[now]=MIN(low[now],low[e2[i].to]);
37     else
38       if(!id[e2[i].to])
39         low[now]=MIN(low[now],dfn[e2[i].to]);
40   }
41   if(dfn[now]==low[now])
42   {
43     id[now]=++num;
44     while(sta[top]!=now){id[sta[top]]=num;--top;}
45     top--;
46   }
47 }
48 int main()
49 {
50   r(n),r(m),r(X);
51   for(re int i=1;i<=m;++i)
52     r(u),r(to),add(u,to,1);
53   for(re int i=1;i<=n;++i)
54     if(!dfn[i])
55       tarjan(i);
56   for(re int i=1;i<=n;++i)
57     w[id[i]]++;
58   cnt=0;
59   for(re int i=1;i<=n;++i)
60     for(re int j=h2[i];j;j=e2[j].nex)
61     {
62       int y=id[e2[j].to],x=id[i];
63       if(x!=y) add(x,y,2),du[y]++;
64     }
65   for(re int i=1;i<=num;++i)
66     if(!du[i]) sta[++top]=i,dp[i]=w[i],ans2[i]=1;
67   for(re int i=1;i<=top;++i)
68   {
69     int x=sta[i];
70     for(re int j=h[x];j;j=e[j].nex)
71     {
72       du[e[j].to]--;
73       if(du[e[j].to]==0) sta[++top]=e[j].to;
74       if(book[e[j].to]) continue;
75       book[e[j].to]=1,sta2[++heap]=e[j].to;
76       if(dp[e[j].to]<dp[x]+w[e[j].to])
77         dp[e[j].to]=dp[x]+w[e[j].to],ans2[e[j].to]=0;
78       if(dp[e[j].to]==dp[x]+w[e[j].to])
79         ans2[e[j].to]=(ans2[e[j].to]+ans2[x])%X;
80     }
81     while(heap){book[sta2[heap]]=0;heap--;}
82     ans=MAX(ans,dp[x]);
83   }
84   ll anse=0;
85   for(int i=1;i<=num;++i)
86     if(dp[i]==ans) anse=(anse+ans2[i])%X;
87   printf("%d\n%lld",ans,anse);
88   return 0;
89 }

 

转载于:https://www.cnblogs.com/dah1314/p/10946339.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值