【ybt金牌导航6-1-5】最大割(线段树分治)(线性基)

最大割

题目链接:ybt金牌导航6-1-5

题目大意

有一些点,会不断加边(原本没有边)。
对于每加一次边之后的图,你要求权值最大的割的权值。
你任选一个点集,然后使得刚好有一个端点在某个点集中的边的集合就是割。
割的权值是边集合中每条边权异或和。

思路

那我们首先不难看到,如果边两个端点都在同一个点,那就贡献一定是 \(0\)
接着,如果有两条权值相同的边连同时两个点,那权值也会抵消。

那我们求异或其实可以用线性基来做。
但容易看到前面的抵消会让线性基要有修改操作,而线性基修改很麻烦。
那也就是说线性基的某个数只会在某个时段出现。
然后就想到了线段树分治。

然后就欢乐搞搞搞了。

然后由于线性基数可以达到 \(2^{1000}\),我们可以用 bitset 来加速。

代码

#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring> 

using namespace std;

typedef bitset <1001> bit;
struct bits {
	bit a[1001];
};
int ID, n, m, x, y;
int lst[501], sn;
bit tmp, a[501];
char s[2001];
vector <bit> tr[4001];

//线性基插入
void add_xxj(bits &x, bit y) {
	for (int i = 1000; i >= 0; i--)
		if (y[i]) {
			if (!x.a[i].any()) {
				x.a[i] = y;
				break;
			}
			y ^= x.a[i];
		}
}

//求最大值并输出
void write(bits x) {
	bit an;
	for (int i = 1000; i >= 0; i--) {
		if (x.a[i].any() && !an[i])
			an ^= x.a[i];
	}
	
	int now = 1000;
	while (now >= 1 && !an[now]) now--;
	for (int i = now; i >= 0; i--)
		putchar(an[i] ? '1' : '0');
	putchar('\n');
}

//线段树分治
void insert_(int now, int l, int r, int L, int R, int x) {
	if (R == 0) return ;
	if (L <= l && r <= R) {
		tr[now].push_back(a[x]);
		return ;
	}
	int mid = (l + r) >> 1;
	if (L <= mid) insert_(now << 1, l, mid, L, R, x);
	if (mid < R) insert_(now << 1 | 1, mid + 1, r, L, R, x);
}

void query_all(int now, int l, int r, bits ans) {
	for (int i = 0; i < tr[now].size(); i++) {
		add_xxj(ans, tr[now][i]);
	}
	
	if (l == r) {
		write(ans);
		return ;
	}
	
	int mid = (l + r) >> 1;
	query_all(now << 1, l, mid, ans);
	query_all(now << 1 | 1, mid + 1, r, ans);
}

int main() {
	scanf("%d", &ID);
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; i++) {
		scanf("%d %d", &x, &y);
		scanf("%s", &s);
		sn = strlen(s);
		tmp.reset();
		for (int j = 0; j < sn; j++)
			tmp[sn - j - 1] = s[j] - '0';//记得倒叙储存
		if (x == y) continue;
		insert_(1, 1, m, lst[x], i - 1, x);
		lst[x] = i; a[x] ^= tmp;
		insert_(1, 1, m, lst[y], i - 1, y);
		lst[y] = i; a[y] ^= tmp;
	}
	
	for (int i = 1; i <= n; i++)//最后到结束的时间段也要记录
		if (lst[i]) insert_(1, 1, m, lst[i], m, i);
	
	bits ans;
	for (int i = 0; i <= 1000; i++) ans.a[i].reset();
	query_all(1, 1, m, ans);
	
	return 0;
}
posted @ 2021-07-06 16:05  あおいSakura  阅读(33)  评论(0编辑  收藏  举报