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

#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;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇