300iq Contest 2 E - Easy Win(最大权线性基)
http://codeforces.com/gym/102331/problem/E
题解:
考虑如何判断若干条边是否有环,pty说他在离散数学课上学过这个:
若有一条边\((x,y)\),则看作一个异或空间的向量,第x维和第y维是1,那么无环相当于向量是线性无关的。
发现这样就可以把边权也带上来。
然后问题就变成了选若干向量线性无关,并且权值最大,对每个前缀都要求。
如果不是对每个前缀求,不难想到直接从大到小排序能加就加,显然是对的。
对每个前缀求,必须按顺序加,多记一个每个基是由原来那些向量异或得来,加入一个向量若被消成0,则替换它的表示中权值最小的即可。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
#define B bitset<128>
const int N = 130;
int n, Q, x, y, v; ll z;
B a[N], b[N]; int bz[N];
ll w[N]; int w0;
ll ans;
void add(B c, int v) {
B d; d.reset();
fd(i, 128, 0) if(c[i]) {
if(!bz[i]) {
bz[i] = 1;
ans += v;
w[++ w0] = v;
d[w0] = 1;
a[i] = c; b[i] = d;
return;
} else {
c ^= a[i], d ^= b[i];
}
}
int f = -1;
fo(i, 1, w0) if(d[i])
if(f == -1 || w[i] < w[f]) f = i;
if(v > w[f]) {
ans += v - w[f];
w[f] = v; d[f] = 0;
fo(i, 0, 128) if(bz[i] && b[i][f]) {
b[i] ^= d;
}
}
}
int main() {
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
scanf("%d %d", &n, &Q);
fo(i, 1, Q) {
scanf("%d %d %lld %d", &x, &y, &z, &v);
x --, y --;
B c; c.reset();
c[x] = 1; c[y] = 1;
fo(j, 0, 60) c[64 + j] = z >> j & 1;
add(c, v);
pp("%lld\n", ans);
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址