JZOJ 5649. 【NOI2018模拟4.13】异或 (线性基高端操作)

https://gmoj.net/senior/#main/show/5649

和这题类似:
http://www.51nod.com/Challenge/Problem.html#problemId=1577

题解:

考虑线段树维护线性基,它TLE了。

考虑离线后从左往右建线性基,注意维护一个最大生成线性基,一个要加入的数若可以被线性基异或出来,找到组成它的数最小的那个,替换就好了。

这个怎么样都要\(O(log^2)\)

考虑改一下线性基的一些定义。

对于每一位的基,记\(b[i]\)表示最右的左端点,满足当前\([b[i],r]\)能搞出这一位的基,也要记一下基是什么。

修改时,如果空的就插进去,不然看谁更小,就保留谁,另一个下去更新,细节见代码。

查询就直接查了。

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 gc getchar
template<class T> void read(T &x) {
	char c = ' '; x = 0; int f = 1;
	while(c != '-' && (c < '0' || c > '9')) c = gc();
	if(c == '-') f = -1, c = gc();
	for(; c >= '0' && c <= '9'; c = gc()) x = x * 10 + c - '0';
}

#define pc putchar
template<class T> void write(T x) {
	int d[30], d0 = 0;
	if(!x) d[++ d0] = 0; else {
		for(; x; x /= 10) d[++ d0] = x % 10;
	}
	while(d0) pc(d[d0 --] + '0');
}

const int N = 1e6 + 5;

int n, a[N];
int Q, x, y, z;

struct nod {
	int a[30], b[30];
	void add(int x, int y) {
		fd(i, 29, 0) if(x >> i & 1) {
			if(a[i]) {
				if(y > b[i]) {
					swap(x, a[i]);
					swap(y, b[i]);
					x ^= a[i];
				} else {
					x ^= a[i];
				}
			} else {
				a[i] = x, b[i] = y;
				break;
			}
		}
	}
	int qry(int x, int L) {
		fd(i, 29, 0) if(a[i]) {
			if(!(x >> i & 1) && L <= b[i]) {
				x ^= a[i];
			}
		}
		return x;
	}
} b[N];

int main() {
	scanf("%d", &n);
	fo(i, 1, n) {
		read(a[i]);
		b[i] = b[i - 1];
		b[i].add(a[i], i);
	}
	scanf("%d", &Q);
	fo(ii, 1, Q) {
		read(x); read(y); read(z);
		write(b[y].qry(z, x));
		pc('\n');
	}
}

猜你喜欢

转载自www.cnblogs.com/coldchair/p/12933810.html
今日推荐