B 酱的无向图 题解

2022-09-19 12:42:16 浏览数 (2)

B 酱的无向图 题解

[mdx_warning]本题目有版权,禁止复制[/mdx_warning]

题目描述

B 酱有n个节点的无向图,初始时图中没有边。他依次向图中加入了m条无向边,并询问你加入每条边后图中桥的个数是多少。被删除后能使图中连通块个数增加的边就称为桥。注意图中可能会出现重边及负环。

输入格式

输入第一行为三个正整数n,m, p, p 的含义将在输出格式中介绍。 接下来 m 行,每行两个正整数 u, v,表示新加入的一条边。

输出格式

为减少输出量,设 ans_i 表示加入第 i 条边后图中桥的个数,请输出left(prod_{i=1}^{m}left(a n s_{i} 1right)right) quad bmod p,其中Pi表示连乘。

输入样例#1

4 4 233 1 2 2 3 3 4 1 4

输出样例#1

24

输入样例#2

6 7 233 6 5 1 2 3 2 1 2 4 6 4 5 1 1

输出样例#2

220

数据范围与约定

对于100%的数据1leq n,mleq 5 times 10^5

思路

对于每一条边,如果加入后无环,那么将其塞入树中,并标出每个点的深度与父亲。 如果是一条非树边,那么就暴力求出他们的LCA(直接选择深度大的往上跳),并且把路径上所有点用并查集缩起来,每个时刻上树上还没有被缩起来的边就是桥。时间复杂度为O(n alpha(n))

Code

代码语言:javascript复制
#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define MAXN 5000010
#define int long long
using namespace std;
inline int read(){
    int res=0,f=1;char ch=getchar();
    while(ch<'0'ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') res=res*10 ch-'0',ch=getchar();
    return res*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x<10) putchar(x '0');
    else{
        write(x/10);
        putchar(x '0');
    }
}
int n,m,mod,ans=1,sum,las,num;
int fa[MAXN],u[MAXN],v[MAXN],g[MAXN],f[MAXN],vis[MAXN],def[MAXN],cnt;
int getfa(int x){
    return x==f[x]?x:f[x]=getfa(f[x]);
}
int fir[MAXN],nxt[MAXN],son[MAXN],tot,w[MAXN];
void add(int x,int y,int z){
      tot;
    nxt[tot]=fir[x];
    fir[x]=tot;
    son[tot]=y;
    w[tot]=z;
}
void dfs(int x){//dfs求每一个点的深度与父亲
    def[x]=def[fa[x]] 1;
    f[x]=x;
    for(int i=fir[x];i;i=nxt[i]){
        int to=son[i];
        if(to==x) continue 
        if(to==fa[x]) continue ;
        fa[to]=x;
        dfs(to);
    }
}
signed main(){
    n=read();m=read();mod=read();las=0;
    for(int i=1;i<=n;i  ) f[i]=i;
    memset(fa,0,sizeof(fa));
    cnt=0;
    for(int i=1;i<=m;i  ){
        u[i]=read();v[i]=read();
        if(getfa(u[i])==getfa(v[i])){
            vis[i]=0;
        }else{
            vis[i]=1;
            add(u[i],v[i],0);cnt  ;
            add(v[i],u[i],0);cnt  ;
            f[f[u[i]]]=v[i];
        }
    }
    for(int i=1;i<=n;i  ){
        if(def[i]==0){
            dfs(i);
        }
    }
    for(int i=1;i<=m;i  ){
        if(vis[i]==1) sum  ;//树边
        else{//非树边
            for(int x=getfa(u[i]),y=getfa(v[i]);x!=y;--sum,x=f[x]=getfa(fa[x])){//求LCA,并且用并查集缩起来
                if(def[x]<def[y]) swap(x,y);//深度大的点向上跳
            }
        }
        ans*=sum 1;ans%=mod;
    }
    write(ans);putchar('n');
    return 0;
}

0 人点赞