CodeForces 91 C.Ski Base(欧拉回路+并查集)

本文介绍了一种用于计算图中动态增加边时迹数量变化的高效算法。通过维护图的连通性和使用矩阵消元原理,该算法能够在每次添加新边后快速更新迹的数量。

Description

一张图,依次将m条边加入,问迹的数量,迹为经过至少一条边的回路,且经过的每条边只经过一次

Input

第一行两个整数n,m表示点数和边数,之后m行每行输入两个整数u,v表示一条边(2n105,1m105)

Output

每加一条边就输出当前图中迹的数量

Sample Input

3 4
1 3
2 3
1 2
1 2

Sample Output

0
0
1
3

Solution

假设经过0条边也是迹,那么初始状态答案是1,之后每加入一条边,如果该边的两个顶点在一个连通分支里则答案乘2,否则答案不变,合并两个顶点所在连通分支,输出的时候答案减一即可,下面证明该结论

考虑关联矩阵MM[i][j]表示第i条边与第j个顶点是否关联,定义两行的异或运算:将两行对应列元素异或得到新的一行,如果从这m行中选出非空行做异或运算得到全是0的一行,说明这些边中每个顶点的度均为偶数,显然存在一个迹(其实就是不一定要经过所有边的欧拉回路)

以此异或运算对该矩阵做消元,最后会有mr(M)0行,这些0行表示其对应的边可以用主对角元是1的那r(M)行(也就是这mn元向量的极大无关组)以异或运算表出,那么从这mr(M)中选取任意行做异或,均可以用极大无关组表出,把这些边放在一起就是一个迹,进而有2mr(M)个迹

每次加一条新边的时候,如果这条新边可以被之前的边表出,那么相当于m加一,r(M)不变,进而答案乘2,否则mr(M)均加一,答案不变,而一条边uv如果可以被之前的边表出,说明之前可以找到一条从uv的路径,即说明u,v在一个连通分支里

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=100005;
#define mod 1000000009
int fa[maxn];
int find(int x)
{
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
} 
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)fa[i]=i;
        int ans=0;
        while(m--)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            a=find(a),b=find(b);
            if(a==b)ans=(ans*2+1)%mod;
            else fa[a]=b;
            printf("%d\n",ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值