CF845G

G. Shortest Path Problem?
time limit per test3 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
You are given an undirected graph with weighted edges. The length of some path between two vertices is the bitwise xor of weights of all edges belonging to this path (if some edge is traversed more than once, then it is included in bitwise xor the same number of times). You have to find the minimum length of path between vertex 1 and vertex n.

Note that graph can contain multiple edges and loops. It is guaranteed that the graph is connected.

Input
The first line contains two numbers n and m (1 ≤ n ≤ 100000, n - 1 ≤ m ≤ 100000) — the number of vertices and the number of edges, respectively.

Then m lines follow, each line containing three integer numbers x, y and w (1 ≤ x, y ≤ n, 0 ≤ w ≤ 108). These numbers denote an edge that connects vertices x and y and has weight w.

Output
Print one number — the minimum length of path between vertices 1 and n.

Examples
input
3 3
1 2 3
1 3 2
3 2 0
output
2
input
2 2
1 1 3
1 2 3
output
0

教你做人场的G题果然有教育意义。

第一个套路和上次金策出的题套路一样,就是直接利用通过1号点出去的环加加减减得到。
高妙之处在于高斯消元,每次消出一个只有以2^i为最高二进制位的数然后for一遍。下次遇见这种模型就这么做。具体见代码。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int N = 100005;
const int M = N * 2;

int fir[N] , ne[M] , to[M] , C[M] , cnt , d[N] , n , m;

int cir[M] , cirnum , fil , pow[31];

bool vis[N];

void add(int x ,int y ,int z) {
    ne[++ cnt] = fir[x]; fir[x] = cnt; to[cnt] = y; C[cnt] = z;
}

void link(int x ,int y ,int z) {
    add(x,y,z); add(y,x,z);
} 

#define Foreachson(i,x) for(int i = fir[x];i;i = ne[i])

void dfs(int x) {
    vis[x] = 1;
    Foreachson(i,x) {
        int V = to[i];
        if(vis[V]) {
            int it = d[x] ^ C[i] ^ d[V];
            if(it != 0)
            cir[++ cirnum] = it;
        }
        else {
            d[V] = d[x] ^ C[i];
            dfs(V);
        }
    }
}

void xiao_yuan(void) {
    for(int i = 30;i >= 0;i --) {
        int k = pow[i];
        int it = fil + 1;
        while(it <= cirnum && !(k & cir[it])) it ++;
        if(it == cirnum + 1) continue;
        fil ++;
        swap(cir[it] , cir[fil]);
        for(int j = 1;j <= cirnum;j ++) if(j != fil){
            if(cir[j] & k) cir[j] ^= cir[fil];
        }
    }
}

void build(void) {
    scanf("%d%d",&n,&m);
    int x ,y,z;
    for(int i = 1;i <= m;i ++) {
        scanf("%d%d%d",&x,&y,&z);
        link(x,y,z);
    }
}

int main() {
    freopen("hack845G.txt","r",stdin);
    pow[0] = 1;
    for(int i = 1;i <= 30;i ++) pow[i] = pow[i - 1] * 2;
    build();
    dfs(1);
    xiao_yuan();
    int ans = d[n];
    for(int i = 1;i <= fil;i ++) ans = min(ans , ans ^ cir[i]);
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值