__builtin_orz @ 2024-09-06 11:54:58
#include<algorithm>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<functional>
#ifdef _WIN32
#define getchar _getchar_nolock
#define putchar _putchar_nolock
#else
#define getchar getchar_unlocked
#define puhchar putchar_unlocked
#endif
#define _N_ 1000005
#define _M_ 10000006
#define MAYBE(ptr,attr)(ptr?ptr->attr:decltype(ptr->attr){})
#define int __uint128_t
int read(){
int x=0,ch;
while(!isdigit(ch=getchar()));
do x=x*10+ch-'0';while(isdigit(ch=getchar()));
return x;
}
void write(int x,int step=' '){
static int o[505];
int tp=0;
while(x>9)o[++tp]=x%10+'0',x/=10;
putchar(x+'0');
while(tp)putchar(o[tp--]);
putchar(step);
}
void new_line(){putchar('\n');}
struct Treap{
Treap *ch[2];
int val,rnk;
Treap(int v){
val=v;
rnk=rand();
ch[0]=ch[1]=nullptr;
}
}*DAG_to[_N_];
void Treap_rotate(Treap *&now,int c){
Treap *tmp=now->ch[c];
now->ch[c]=tmp->ch[!c];
tmp->ch[!c]=now;
now=tmp;
}
void Treap_insert(Treap *&now,int x){
if(!now)now=new Treap(x);
else if(x<now->val){
Treap_insert(now->ch[0],x);
if(now->ch[0]->rnk<now->rnk)
Treap_rotate(now,0);
}else if(x>now->val){
Treap_insert(now->ch[1],x);
if(now->ch[1]->rnk<now->rnk)
Treap_rotate(now,1);
}
}
void Treap_each(Treap *now,std::function<void(int)>f){
if(now){
f(now->val);
Treap_each(now->ch[0],f);
Treap_each(now->ch[1],f);
}
}
struct CFS{
int val;
CFS *nxt;
CFS(int val,CFS *nxt=nullptr):val(val),nxt(nxt){}
}*G_to[_N_];
void CFS_add_edge(CFS *&head,int val){head=new CFS(val,head);}
void CFS_each(CFS *head,std::function<void(int)>f){
for(CFS *i=head;i;i=i->nxt)
f(i->val);
}
#define EACH(type,name,...)type##_each(name,[&](__VA_ARGS__){
#define END });
int SCC_low[_N_],SCC_dfn[_N_],SCC_dfn_cnt;
int SCC_stk[_N_],SCC_top;
int SCC_scc[_N_],SCC_scc_cnt;
int SCC_scc_siz[_N_];
void tarjan(int now){
now[SCC_low]=now[SCC_dfn]=++SCC_dfn_cnt;
SCC_stk[++SCC_top]=now;
EACH(CFS,G_to[now],int to)
if(!to[SCC_dfn]){
tarjan(to);
now[SCC_low]=std::min(now[SCC_low],to[SCC_low]);
}else if(!to[SCC_scc])
now[SCC_low]=std::min(now[SCC_low],to[SCC_dfn]);
END
if(now[SCC_dfn]==now[SCC_low]){
SCC_scc_cnt++;
int tmp;
do{
tmp=SCC_stk[SCC_top];
tmp[SCC_scc]=SCC_scc_cnt;
SCC_scc_cnt[SCC_scc_siz]++;
SCC_top--;
}while(tmp!=now);
}
}
int ans[_N_],kind[_N_];
void topo(int now){
now[ans]=now[SCC_scc_siz];
now[kind]=1;
int delta=0;
EACH(Treap,now[DAG_to],int to)
if(!to[ans])
topo(to);
if(to[ans]>delta){
delta=to[ans];
now[kind]=0;
}
if(to[ans]==delta)
now[kind]++;
END
now[ans]+=delta;
}
signed main(){
srand(time(nullptr));
int n=read(),m=read(),MOD=read();
for(int i=1;i<=m;i++){
int f=read(),t=read();
CFS_add_edge(G_to[f],t);
}
for(int i=1;i<=n;i++)
if(!SCC_scc[i])
tarjan(i);
for(int i=1;i<=n;i++)
EACH(CFS,G_to[i],int to)
if(i[SCC_scc]!=to[SCC_scc])
Treap_insert(i[SCC_scc][DAG_to],to[SCC_scc]);
END
int real_ans=0,real_kind=0;;
for(int i=1;i<=SCC_scc_cnt;i++){
if(!i[ans])
topo(i);
if(i[ans]>real_ans){
real_ans=i[ans];
real_kind=0;
}
if(i[ans]==real_ans)
real_kind=(real_kind+i[kind])%MOD;
}
write(real_ans,'\n');
write(real_kind);
return 0;
}
by Cuxhin @ 2024-09-06 11:57:16
蚂蜂太差,不看
by Amadeus004 @ 2024-09-06 12:00:33
这码量都快赶上树剖+可持久化线段树了