zoukankan      html  css  js  c++  java
  • 【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('
    ');
    }
    
    //线段树分治
    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;
    }
    
  • 相关阅读:
    Jupsh_flutter Android 收不到消息 / 排查不出请根据第 9 点说明提供信息
    angular表单 Dom获取表单值以及双向数据绑定
    angular中的组件以及组件中的模板合成
    Flutter开发的app进行设备判断是Ios还是android
    Java的封装
    GCD编程 之 略微提高篇
    多线程基础(六)GCD基础
    我遇到的CocoaPods的问题(也许后期会解决,持续更新)
    iOS之通过PaintCode快速实现交互动画的最方便方法 未解问题
    多线程基础(五)NSThread线程通信
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBT_JPDH_6-1-5.html
Copyright © 2011-2022 走看看