前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >B 酱的无向图 题解

B 酱的无向图 题解

作者头像
yzxoi
发布2022-09-19 12:42:16
8160
发布2022-09-19 12:42:16
举报
文章被收录于专栏:OIOI

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}+1\right)\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%的数据1\leq n,m\leq 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%10+'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;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-04-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • B 酱的无向图 题解
    • 题目描述
      • 输入格式
        • 输出格式
          • 输入样例#1
            • 输出样例#1
              • 输入样例#2
                • 输出样例#2
                  • 数据范围与约定
                    • 思路
                      • Code
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档