zoukankan      html  css  js  c++  java
  • BZOJ3569-DZY Loves Chinese II

    BZOJ3569-DZY Loves Chinese II

      题意:

      题解:

        好神的题啊...

        先求出原图的任意一棵生成树,然后图中的边就分为了生成树中的边和非生成树中的边.对于非生成树中的边,你给它rand一个权值,对于生成树中的边, 它的权值就是跨过它的非生成树中边的权值的xor和.然后对于每个询问,如果在给出的边中选出一些边是它们的权值xor为0,那么就图就不连通,否则连通.

        该做法正确性证明见文末链接.

        对于求生成树中的边的权值可以用差分求.对于求一个集合是否有xor为0的子集,我好像瞎搞了一个线性基做法,就是把一个数加入线性基后变成了0,那就说明有xor为0的子集.

    #include<cstdio>
    #include<vector>
    #include<cstdlib>
    using namespace std;
    typedef long long ll;
    const int maxn=100000,maxm=500000,lgn=18,lgv=62;
    int n,m,fa[maxn+10],dep[maxn+10]; ll c[maxn+10],d[lgv+1],q,pre;
    vector<int> G[maxn+10];
    int getf(int x){return fa[x]==x?x:fa[x]=getf(fa[x]);}
    struct edge{
        int u,v,w; bool type;
        ll value;
    }eg[maxm+10];
    void dfs(int x,int fa){
        dep[x]=dep[fa]+1;
        for(int i=0;i<G[x].size();++i){
            int e=G[x][i]; if(e!=fa){
                dfs(e,x); c[x]^=c[e];
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) fa[i]=i;
        for(int i=1;i<=m;++i){
            scanf("%d%d",&eg[i].u,&eg[i].v);
            if(getf(eg[i].u)==getf(eg[i].v)){
                eg[i].type=1; eg[i].value=1ll*rand()*rand()*rand()*rand();
                c[eg[i].u]^=eg[i].value; c[eg[i].v]^=eg[i].value;
            }else{
                fa[getf(eg[i].u)]=getf(eg[i].v);
                G[eg[i].u].push_back(eg[i].v); G[eg[i].v].push_back(eg[i].u);
            }
        }
        dfs(1,0);
        for(int i=1;i<=m;++i) if(!eg[i].type)
            if(dep[eg[i].u]>dep[eg[i].v]) eg[i].value=c[eg[i].u];
        else eg[i].value=c[eg[i].v];
        scanf("%d",&q);
        for(;q--;){
            int k,x; scanf("%d",&k); bool suc=0;
            for(int i=0;i<=lgv;++i) d[i]=0;
            for(;k--;){
                scanf("%d",&x); x^=pre; ll now=eg[x].value;
                for(int i=lgv;i>=0;--i)
                    if(now>>i&1)
                        if(!d[i]){
                            d[i]=now; break;
                        }else now^=d[i];
                if(!now) suc=1;
            }
            printf("%s
    ",suc?"Disconnected":"Connected");
            pre+=!suc;
        }
        return 0;
    }

         update:刚刚在uoj上看见了一个非常妙的证明:http://wuhongxun.blog.uoj.ac/blog/3003.

  • 相关阅读:
    MySQL——sql语句处理时间——时间、字符串、时间戳互相转换
    MySQL——sql语句处理时间——日期加减天数
    Spring Boot——jpaProperties.getHibernateProperties()的使用
    Spring Boot——SpringBoot2+JPA+druid配置多数据源
    Spring Boot——log4j日志配置案例
    git命令——git 分支操作
    windows如何删除默认打开方式
    excel导出出现弹框
    笔记
    javascript中三个等号"==="是什么意思
  • 原文地址:https://www.cnblogs.com/jxcakak/p/7638508.html
Copyright © 2011-2022 走看看