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);
	}
}
posted @ 2020-05-28 21:23  Cold_Chair  阅读(557)  评论(0编辑  收藏  举报