ZJOI 2007最大半连通子图--Tarjan缩点+拓扑排序
作者:互联网
Loj 10092
题目分析:
- 简化题意:找出图中最长链以及最长链个数
- 先Tarjan缩点,重新建图;
- 维护一个d[i]表示临时到i的最长链的长度,ac[i]表示到i号节点且为最长链的方案数
- 注意拓扑排序先将所有入度为0的点压入栈,每一次扩展栈中的点,删边之后,若更新的v入度也变为0,将v也要压入栈内!!!!!!!!!!!!!!!
Code:
#include <bits/stdc++.h>
using namespace std;
#define maxn 100010
#define maxm 1000010
int ans=0,du[maxn],d[maxn],ac[maxn],sum[maxn],n,m,mod,head[maxn],size=0,dfn[maxn],low[maxn],st[maxn],top=0,co[maxn],col=0,cnt=0;
struct edge {
int u,v,nxt;
}e[maxm];
struct node {
int v,nxt;
}ne[maxm];
inline void init_() {
freopen("a.txt","r",stdin);
}
inline int read_() {
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
return x*f;
}
inline void clean_() {
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(co,0,sizeof(co));
memset(sum,0,sizeof(sum));
memset(du,0,sizeof(du));
memset(d,0,sizeof(d));
memset(ac,0,sizeof(ac));
}
inline void add_(int u,int v) {
e[++size].u=u;
e[size].v=v;
e[size].nxt=head[u];
head[u]=size;
}
void Tarjan_(int u) {
dfn[u]=low[u]=++cnt;
st[++top]=u;
for(int i=head[u];~i;i=e[i].nxt) {
int v=e[i].v;
if(!dfn[v]) {
Tarjan_(v);
low[u]=min(low[u],low[v]);
}
else if(!co[v]) {
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]) {
co[u]=++col;
++sum[col];
while(st[top]!=u) {
co[st[top]]=col;
++sum[col];
--top;
}
--top;
}
}
inline bool cmp_(edge aa,edge bb) {
if(aa.u==bb.u) return aa.v<bb.v;
else return aa.u<bb.u;
}
inline void new_add_(int u,int v) {
ne[++size].v=v;
ne[size].nxt=head[u];
head[u]=size;
}
inline void rebuild_() {
for(int i=1;i<=m;++i) {
int u=co[e[i].u],v=co[e[i].v];
e[i].u=u;e[i].v=v;
}
sort(e+1,e+m+1,cmp_);
memset(head,-1,sizeof(head));
size=0;
int last_u=-1,last_v=-1;
for(int i=1;i<=m;++i) {
if(e[i].u==e[i].v) continue;
if(e[i].u==last_u&&e[i].v==last_v) continue;
new_add_(e[i].u,e[i].v);
last_u=e[i].u;last_v=e[i].v;
++du[e[i].v];
}
}
inline void first_topu_() {
top=0;
for(int i=1;i<=col;++i) {
if(!du[i]) {
st[++top]=i;
d[i]=sum[i];
ac[i]=1;
if(d[i]>d[ans]) ans=i;
}
}
}
inline void topu_() {
int pdc=0;
while(pdc<=top) {
int u=st[++pdc];
for(int i=head[u];~i;i=ne[i].nxt) {
int v=ne[i].v;
--du[v];
if(d[v]<d[u]+sum[v]) {
d[v]=d[u]+sum[v];
ac[v]=0;
if(d[v]>d[ans]) ans=v;
}
if(d[v]==d[u]+sum[v]) {
ac[v]=(ac[u]+ac[v])%mod;
}
if(!du[v]) st[++top]=v;
}
}
}
int AK=0;
inline void ask_ac_() {
for(int i=1;i<=col;++i) {
if(d[ans]==d[i]) {
AK+=ac[i]%mod;
}
}
}
void readda_() {
clean_();
n=read_();m=read_();mod=read_();
int x,y;
for(int i=1;i<=m;++i) {
x=read_();y=read_();
add_(x,y);
}
for(int i=1;i<=n;++i) {
if(!dfn[i]) Tarjan_(i);
}
rebuild_();
first_topu_();
topu_();
ask_ac_();
printf("%d\n%d",d[ans],AK%mod);
}
int main() {
init_();
readda_();
return 0;
}
标签:缩点,ac,ZJOI,int,void,子图,maxn,ans,inline 来源: https://blog.csdn.net/weixin_44574520/article/details/97619229