CF553C Love Triangles(带权并查集)

Posted 吃花椒的妙酱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF553C Love Triangles(带权并查集)相关的知识,希望对你有一定的参考价值。

维护集合关系,可以用拓展域并查集,2sat,带权并查集

其中带权并查集难理解(不过代码短,个人认为

2sat和并查集的主要区别在于,并查集可以维护两者是否属于一类的问题,而2sat相比于其维护的范围更广一点,可以带逻辑的推理p->q,非p->q之类的...

以下用带权并查集..

CF553C Love Triangles

给出n个点,要求构造合法的完全图,已经给出了一些边。

边有爱边和恨边,其中任意三个点,连成的边合法的组合有爱爱爱,爱恨恨。

问符合要求的完全图的数量,对1e9+7取模.n<=1e5

思路:

显然对于三个点,若已知两边则第三边也确定了。如果已知一边,则其他两边有两种选择

不妨设爱的边权为0,恨为1,那么符合的三个点之间三条边的异或值为0。

我们把点连好后,输入完,整张图就是若干连通块(暂不考虑任意三点的条件

我们把连通块缩点,我们考虑任意两个极大连通块的关系,设块1位s1,块2为s2,假设现在加一条边使得,s1s2连通,则对于任意u∈s1,v∈s2,u和v的关系就确定下来了(假设在xy间加边,那么在s1s2中和xy相连的点都可以慢慢确定下来,已知2推1),换句话就是说,任意两个极大连通块间有两种连法,假设缩点后有m个块,那么答案就是2^(m-1)

接下来考虑维护这个边权01的正确性

考虑给每个点赋值,若边权为0,则u=0,v=0 / u=1,v=1,进一步边权则代表两点是否属于一类

我们用带权并查集维护集合内点与根是否属于一类,这个信息(0一类,1不是一类

输入的时候把边权反一下

假设我们现在要合并uv,若uv在同一集合内,显然uv与root组成的三元环异或值为0,如果不是则不合法

若不在一集合内,根据传递性,合并的时候,root_u -> u -> v -> root_v ,因为异或是无向的,所以root_u与root_v的新边的值就是uv和输入的边权z的异或和

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<cstring>
#include<string>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<deque>
#include<set>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pii pair<int ,int >
#define pb(v) push_back(v)
#define all(v) v.begin(),v.end()
#define int long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define endl "\\n"
#define fi first
#define se second
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define AC return 0
const int N=1e5+10;
const int mod=1e9+7;
const double eps=1e-8;
int n,m;
int fa[N],g[N];
int find(int x)

    if( fa[x] == x)  return x;
    int t = find(fa[x]);
    g[x] ^= g[fa[x]];
    return fa[x] = t;

ll qsm(int a,int b  )

    int ans=1,temp=a;
    while( b )
    
        if( b&1 ) ans = (ans * temp )%mod;
        temp = (temp * temp)%mod;
        b>>=1;
    
    return ans;

signed main()

#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif  
    IOS;
    cin>>n>>m;
    _for(i,1,n) fa[i]=i;
    _for(i,1,m)
    
        int x,y,z;cin>>x>>y>>z;
        int fx = find(x);
        int fy = find(y);
        int temp = g[x]^g[y];
        z^=1;
        if( fx!=fy )
        
            fa[fx] = fy;
            g[fx] = g[x]^g[y]^z;
        
        else//如果是一类,x,y,fy三元环异或为0
        
            if( temp^z ) return cout<<0<<endl,0;
        
    
    int tot=0;
    _for(i,1,n)
    
        if( i==find(i) ) tot++;
    
    int ans = qsm(2,tot-1);
    cout<<ans<<endl;
    AC;

以上是关于CF553C Love Triangles(带权并查集)的主要内容,如果未能解决你的问题,请参考以下文章

codeforces553C Love Triangles

cf Round #309 (Div. 2) E - Love Triangles(二分图染色)

CF1167C News Distribution 带权并查集

带权并查集

CF571D Campus

「带权并查集」奇偶游戏