[BZOJ2115][Wc2011] Xor && dfs+高斯消元

首先我们用dfs确定一条1到n的路径 用d[i]表示1到i的xor值 

这条路径上肯定会出现很多环 那我们就统计环的xor值

这个时候我们可以发现 环的xor值等于d[u] ^ d[v] ^ w(u, v) 因为1到u和1到v路径重合的部分被异或了两遍直接去掉

然后我们可以对环的xor值进行高斯消元的操作解出最大值

注意 环有m-n+1个可能大于n

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define SF scanf
#define PF printf
using namespace std;
typedef long long LL;
const int MAXN = 50000;
const int MAXM = 100000;
struct Node {
    int v, next;
    LL wt;
} Edge[MAXM*2+10];
int adj[MAXN+10], ecnt, n, m, tot;
bool vis[MAXN+10];
LL d[MAXN+10], A[MAXM*2+10], ans;
void addedge(int u, int v, LL wt) {
    Node &e = Edge[ecnt];
    e.v = v; e.wt = wt; e.next = adj[u]; adj[u] = ecnt++;
}
void add(int u, int v, LL wt) {
    addedge(u, v, wt); addedge(v, u, wt);
}
void dfs(int u) {
    vis[u] = true;
    for(int i = adj[u]; ~i; i = Edge[i].next) {
        Node &e = Edge[i];
        if(!vis[e.v]) {
            d[e.v] = d[u] ^ e.wt;
            dfs(e.v);
        }
        else A[tot++] = d[e.v] ^ d[u] ^ e.wt;
    }
}
int gauss() {
    int row, col;
    for(row = 0, col = 63; col >= 0 && row < tot; col--, row++) {
        int r = row;
        for(r = row; r < tot; r++) if(A[r] & (1LL << col)) break;
        if(!(A[r] & (1LL << col))) {
            row--; continue;
        }
        if(r != row) swap(A[r], A[row]);
        for(int i = 0; i < tot; i++) if(i != row && A[i] & (1LL << col)) A[i] ^= A[row];
    }
    return row;
}
int main() {
    memset(adj, -1, sizeof(adj));
    SF("%d%d", &n, &m); 
    for(int i = 1; i <= m; i++) {
        int u, v; LL wt;
        cin >> u >> v >> wt;
        add(u, v, wt);
    }
    dfs(1);
    int row = gauss();
    ans = d[n];
    for(int i = 0; i < row; i++) 
        if((ans ^ A[i]) > ans)
            ans ^= A[i];
    cout << ans;
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值