题目大意:
n个点,m条边,问点1走到点n的最大路径and和。
n
<
=
1
0
5
,
m
<
=
5
∗
1
0
5
,
边
权
<
2
63
n<=10^5,m<=5*10^5,边权<2^{63}
n<=105,m<=5∗105,边权<263
分析:
因为and其实是二进制下的逐位运算,
所以我们可以贪心从二进制的高位开始枚举,
利用并查集判断这一位是否能被加入答案中,
这样显然最优
代码:
#pragma GCC optimize(3)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
#define N 100005
#define M 62
using namespace std;
typedef long long ll;
struct Node{
int u, v; ll w;
}e[N*5];
int f[N], n, m;
void read(int &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
x = x * f;
}
void read1(ll &x) {
ll f = 1ll; x = 0ll; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s >= '0' && s <= '9') { x = x * 10ll + (s - '0'); s = getchar(); }
x = x * f;
}
bool cmp(Node aa, Node bb) {
return aa.w > bb.w;
}
int Find(int x) {
return (f[x] == x) ? x : (f[x] = Find(f[x]));
}
int main() {
read(n); read(m);
rep(i, 1, m) read(e[i].u), read(e[i].v), read1(e[i].w);
sort(e + 1, e + m + 1, cmp);
int R = n; ll ans = 0;
rwp(i, M, 0) if ((1ll << i) <= e[n].w) { R = i; break; }
int xx, yy;
rwp(k, R, 0) {
ans |= (1ll << k);
rep(i, 1, n) f[i] = i;
rep(i, 1, m)
if (e[i].w >= ans) {
xx = Find(e[i].u);
yy = Find(e[i].v);
if ((e[i].w & ans) == ans && xx != yy) f[xx] = yy;
}
xx = Find(1);
yy = Find(n);
if (xx != yy) ans ^= (1ll << k);
}
printf("%lld\n", ans);
return 0;
}