zoukankan      html  css  js  c++  java
  • 【集训队互测2015】最大异或和

    首先不知道有没有神仙线段树分治过的。

    首先一个较为显然的性质:

    [mathrm{Span}{v_1, v_2, dots, v_n} = mathrm{Span}{v_1, v_2 - v_1, dots, v_n - v_{n - 1}} ]

    这个启发我们维护差分序列,此时1操作变成了单点异或,2操作变成了单点异或以及区间清空。

    但是这道题维护的是线性基,所以要用带删除的线性基实现。(具体见【集训队作业2018】围绕着我们的圆环)

    此时单点异或显然可以变成插入再删除。因为线性基的时间复杂度,此时暴力清空也没问题。

    因为每次操作最多使两个位置非负,暴力清空时特判空向量,此时可以摊还分析,复杂度正确。

    因此复杂度为 (O(frac{(n+m)mQ}{omega}))

    这次优化了带删除线性基的代码(从虞大那里参考了部分写法)

    #include <bits/stdc++.h>
    
    const int MAXN = 2048;
    typedef std::bitset<MAXN> B;
    int n, m, Q;
    B frm[MAXN], A[MAXN], arr[MAXN];
    int bse[MAXN], isb[MAXN];
    B read() {
    	static B t; t.reset();
    	static char buf[MAXN]; std::cin >> buf;
    	for (int i = 1; i <= m; ++i) if (buf[i - 1] & 1) t.set(m - i + 1);
    	return t;
    }
    void insert(int at) {
    	for (int i = m; i; --i) if (A[at].test(i)) {
    		if (bse[i]) A[at] ^= A[bse[i]], frm[at] ^= frm[bse[i]];
    		else { isb[bse[i] = at] = i; break; }
    	}
    }
    void modify(int at, B v) {
    	if (v.none()) return ;
    	int ax = 0; isb[0] = 2001;
    	for (int i = 1; i <= n; ++i)
    		if (frm[i].test(at))
    			isb[i] < isb[ax] ? ax = i : 0;
    	for (int i = 1; i <= n; ++i)
    		if (i != ax && frm[i].test(at))
    			A[i] ^= A[ax], frm[i] ^= frm[ax];
    	if (isb[ax]) bse[isb[ax]] = 0, isb[ax] = 0;
    	A[ax] ^= v, insert(ax);
    }
    void output(const B & x) {
    	static char buf[MAXN];
    	for (int i = 1; i <= m; ++i) buf[i - 1] = x[m - i + 1] + '0';
    	std::cout << buf << std::endl;
    }
    B query() {
    	static B t; t.reset();
    	for (int i = m; i; --i)
    		if (!t.test(i) && bse[i])
    			t ^= A[bse[i]];
    	return t;
    }
    int main() {
    	std::ios_base::sync_with_stdio(false), std::cin.tie(0);
    	std::cin >> n >> m >> Q;
    	B t;
    	for (int i = 1; i <= n; ++i)
    		A[i] = (arr[i] = read()) ^ arr[i - 1], frm[i].set(i), insert(i);
    	while (Q --> 0) {
    		int opt, t1, t2;
    		std::cin >> opt;
    		if (opt == 1) {
    			std::cin >> t1 >> t2; t = read();
    			modify(t1, t);
    			if (t2 < n) modify(t2 + 1, t);
    			for (int i = t1; i <= t2; ++i) arr[i] ^= t;
    		} else if (opt == 2) {
    			std::cin >> t1 >> t2; t = read();
    			modify(t1, arr[t1] ^ t);
    			if (t2 < n) modify(t2 + 1, arr[t2] ^ t);
    			for (int i = t1 + 1; i <= t2; ++i)
    				modify(i, arr[i] ^ arr[i - 1]);
    			for (int i = t1; i <= t2; ++i) arr[i] = t;
    		} else if (opt == 3) output(query());
    	}
    	return 0;
    }
    
  • 相关阅读:
    10个最好的游戏开发在线资源
    程序员什么时候该考虑辞职
    程序员常去的14个顶级开发社区
    如何成为10倍速的程序员
    (通用)深度学习环境搭建:tensorflow安装教程及常见错误解决
    20行JS代码实现贪吃蛇
    程序员必备工具目录
    发布 Google Chrome插件教程
    高并发思路
    30分钟入门Java
  • 原文地址:https://www.cnblogs.com/daklqw/p/11545965.html
Copyright © 2011-2022 走看看