• p4434 [COCI2017-2018#2] ​​Usmjeri


    思路

    并查集的好题
    考虑到求满足条件限制的方案数,显然观察样例可知结果就是2^x,x是互不影响的边的集合数量
    然后考虑如何求互不影响的边的集合数量
    可以使用并查集,用i和i+n表示这个点的父亲连向它的边的两种指向,然后每次合并,u->lca,v->lca,如果lca不是u或v,合并u+n和v,v+n和u即可
    为了保证复杂度,需要路径压缩一下
    但是要注意这样的话,合并u+n和v,v+n和u必须在后面进行,不然会破坏树的结构
    最后答案是(2^{x}),x是并查集个数/2

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int v[600400],fir[300400],nxt[600400],cnt;
    void addedge(int ui,int vi){
        ++cnt;
        v[cnt]=vi;
        nxt[cnt]=fir[ui];
        fir[ui]=cnt;
    }
    int jump[300400][20],dep[300400];
    void dfs(int u,int f){
        jump[u][0]=f;
        dep[u]=dep[f]+1;
        for(int i=1;i<20;i++)
            jump[u][i]=jump[jump[u][i-1]][i-1];
        for(int i=fir[u];i;i=nxt[i]){
            if(v[i]==f)
                continue;
            dfs(v[i],u);
        }
    }
    int lca(int x,int y){
        if(dep[x]<dep[y])
            swap(x,y);
        for(int i=19;i>=0;i--)
            if(dep[jump[x][i]]>=dep[y])
                x=jump[x][i];
        if(x==y)
            return x;
        for(int i=19;i>=0;i--)
            if(jump[x][i]!=jump[y][i])
                x=jump[x][i],y=jump[y][i];
        return jump[x][0];
    }
    const int MOD = 1000000007;
    int pow(int a,int b){
        int ans=1;
        while(b){
            if(b&1)
                ans=(1LL*ans*a)%MOD;
            a=(1LL*a*a)%MOD;
            b>>=1;
        }
        return ans;
    }
    int fa[600400],n,m;
    int find(int x){
        if(fa[x]==x)
            return x;
        else
            return fa[x]=find(fa[x]);
    }
    void merge(int x,int Lca){
        while(dep[jump[x][0]]>dep[Lca]){
            int f=jump[x][0];
            fa[find(x)]=find(f);
            fa[find(x+n)]=find(f+n);
            x=find(f);
        }   
    }
    int ta[300300],tb[300300],Lca[300300];
    int main(){
        freopen("test.in","r",stdin);
        // freopen("test.out","w",stdout);
        scanf("%d %d",&n,&m);
        for(int i=1;i<=2*n;i++)
            fa[i]=i;
        for(int i=1;i<n;i++){
            int a,b;
            scanf("%d %d",&a,&b);
            addedge(a,b);
            addedge(b,a);
        }
        dfs(1,0);
        for(int i=1;i<=m;i++){
            scanf("%d %d",&ta[i],&tb[i]);
            Lca[i]=lca(ta[i],tb[i]);
            merge(ta[i],Lca[i]);
            merge(tb[i],Lca[i]);
        }
        for(int i=1;i<=m;i++){
            if(Lca[i]!=ta[i]&&Lca[i]!=tb[i]){
                fa[find(ta[i]+n)]=find(tb[i]);
                fa[find(tb[i]+n)]=find(ta[i]);
            }
        }
        int ans=0;
        for(int i=2;i<=n;i++){
            if(find(i)==find(i+n)){
                printf("0
    ");
                return 0;
            }
            ans+=(find(i)==i);
            ans+=(find(i+n)==(i+n));
        }
        printf("%d
    ",pow(2,ans/2));
        return 0;
    }
    
  • 相关阅读:
    smbmnt
    smbd
    smbcontrol
    smbclient
    smb.conf
    sleep
    size
    oracle-rman-1
    cURL 学习笔记与总结(5)用 cURL 访问 HTTPS 资源
    Java实现 LeetCode 90 子集 II(二)
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10804440.html
Copyright © 2020-2023  润新知