CF553C Love Triangles


題目鏈接

題意:給定n個點,給出一些邊權為0/1的邊,構造完全圖,滿足對於任何一個三元環,三條邊權和為奇。求符合條件的完全圖數量,對\(1e9+7\)取模。

分析:其實原題給定的邊權是love/hate,love即1,hate即0。

所以對於三元環而言,只存在“愛愛愛”或“愛恨恨”。

如果我們按此討論點與點之間的關系,我們會想到什么?

敵人的敵人就是朋友,朋友的朋友還是朋友。

那么這道題就和[BOI2003]團伙的描述有些類似了。

我們顯然可以用到並查集。

團伙那題,我們確定兩點關系可以建立補集,也可以使用帶權並查集。

這題,我們發現,一個集合是否有補集在統計答案時並無差別(都相當於一個點),所以我們使用帶權並查集。

帶權並查集的方法就十分顯然了,對於love的邊,連一條權值為0的邊,對於hate的邊,連一條權值為1的邊(注意與題目所給的相反)。每次連邊是順便檢查兩點關系。

最后我們得到\(k\)個集合,把\(k\)個集合放入兩個桶中,有\(2^k\)種方法,再去重,最后的答案就是\(2^{k-1}\)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int fa[100100], val[100100];//fa是所在集合,val是與祖先關系

inline int read()// Fast input
{
    int x=0,f=1; char ch=getchar();
    for (; ch<'0' || ch>'9'; ch=getchar()) if (ch=='-') f=-1;
    for (; ch>='0' && ch<='9'; ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}

int find(int x)//帶權並查集
{
    if (fa[x]==x) return x;
    int t=find(fa[x]);
    val[x]^=val[fa[x]];
    return fa[x]=t;
}

int main()
{
    int n=read(), k=read();
    for (int i=1; i<=n; i++) fa[i]=i;
    for (int i=1; i<=k; i++)
    {
        int u=read(), v=read(), w=read()^1;
        int fu=find(u), fv=find(v);
        if (fu!=fv)
        {
            fa[fv]=fu;
            val[fv]=val[u]^val[v]^w;
        }
        else
        {
            if (w && !(val[u]^val[v])) {puts("0"); return 0;}
            if (!w && val[u]^val[v]) {puts("0"); return 0;}
        }
    }
    int res=0, ans=1;
    for (int i=1; i<=n; i++) if (find(i)==i) res++;
    for (int i=1; i<=res-1; i++) ans=(ans*2)%mod;//(其實可以寫quick_power的qwq
    printf("%d\n",ans);
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM