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 ,否则答案不变,合并两个顶点所在连通分支,输出的时候答案减一即可,下面证明该结论

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

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

每次加一条新边的时候,如果这条新边可以被之前的边表出,那么相当于 m 加一,r(M)不变,进而答案乘 2 ,否则m r(M) 均加一,答案不变,而一条边 uv 如果可以被之前的边表出,说明之前可以找到一条从 u v的路径,即说明 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值