BZOJ 2115 Xor(dfs&独立回路&异或消元)

学习的秦总的写法写的 dfs 找独立回路和异或消元:秦总博客

独立回路的定义和独立回路个数 =MN+1 的证明,博客里面都有,但是 dfs 找的过程好像需要 2 倍的空间,不能理解。。。

分析:这题要明白一个东西,u>v的所有路径可以由 u>v 的一条任意路径+该图的所有独立回路的线性组合完成,其实想一想还是很好理解的,有一点很重要:比如 1>7 是一条路,然后怎么进过回路 2>3,3>4,4>2 ,因为整个图是连通的,所以 1 7点必然有一个点在一个回路里面,这样这个回路走两遍就不影响异或值了,这个时候回路上面的所有点又可以走一个回路,所以如果一直这样拓展一定能够走到 2>3,3>4,4>2 这条回路,并且其他回路都自己抵消了。

附上代码:

#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y)  for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)

using namespace std;

const int maxn = 50050;
const int maxm = 100010;

int head[maxn],edge_cnt;

struct Edge{
    int u,v,nt;
    LL val;
}edge[maxm<<1];

void add_edge(int u,int v,LL val){
    edge[edge_cnt].u = u;
    edge[edge_cnt].v = v;
    edge[edge_cnt].val = val;
    edge[edge_cnt].nt = head[u];
    head[u] = edge_cnt++;
}

int n,m,tot;

LL val[maxm<<1];
LL d[maxn];
bool vis[maxn];

void Build_Graph(){
    memset(vis,false,sizeof(vis));
    edge_cnt = 0;
    memset(head,-1,sizeof(head));
    int u,v;
    LL val;
    FOR(i,0,m){
        scanf("%d%d%lld",&u,&v,&val);
        add_edge(u,v,val);
        add_edge(v,u,val);
    }
}

void dfs(int u,int fa){
    vis[u] = true;
    for(int i = head[u];i != -1;i = edge[i].nt){
        int v = edge[i].v;
        if(v == fa) continue;
        if(!vis[v]){
            d[v] = d[u] ^ edge[i].val;
            dfs(v,u);
        }
        else{
            val[tot++] = d[u]^d[v]^edge[i].val;
        }
    }
}

int xorguass(){
    int row = 0;
    for(int i = 62;i >= 0;-- i){
        int j;
        for(j = row;j < tot;++ j) {
            if(val[j] & (1LL<<i)) break;
        }
        if(j != tot){
            swap(val[j],val[row]);
            for(j = 0;j < tot;++ j){
                if(j == row)    continue;
                if(val[j] & (1LL<<i)){
                    val[j] ^= val[row];
                }
            }
            ++ row;
        }
    }
    return row;
}

void work(){
    LL ans = d[n];
    n = xorguass();
    FOR(i,0,n)  ans = max(ans,ans^val[i]);
    printf("%lld\n",ans);
}
int main()
{
    //freopen("test.in","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        Build_Graph();
        tot = 0;
        d[1] = 0;
        dfs(1,-1);
        work();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值