【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;
}