bzoj 4184 Shallot
有一个一开始为空的集合,每次加入一个数或者删除一个数,每次查询这个集合选出若干个数异或起来的最大结果
$n \leq 100000$
sol:
学了一波线性基
大概就是
1.插入一个数(其中 v 的大小是 logn)
void add(int x) { for(int i=0;i<v.size();i++) if(x > (x ^ v[i]))x ^= v[i]; if(x) { v.push_back(x); for(int i=v.size()-1;i;i--) if(v[i] > v[i - 1])swap(v[i],v[i - 1]); } }
2.查询当前集合最大异或和
int cal() { int ret = 0; for(int i=0;i<v.size();i++) if(ret < (ret ^ v[i])) ret ^= v[i]; return ret; }
其余的操作就没有了,合并的话是启发式合并,删除不资瓷,v 的大小就是当前极大线性无关集的大小
这道题一眼线段树分治,然后线性基裸题
#include<bits/stdc++.h> #define LL long long using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0'; return x * f; } const int maxn = 500010; int n,a[maxn],last[maxn]; map<int,int> hsh; #define ls (x << 1) #define rs ((x << 1) | 1) struct Base { vector<int> v; void add(int x) { for(int i=0;i<v.size();i++) if(x > (x ^ v[i]))x ^= v[i]; if(x) { v.push_back(x); for(int i=v.size()-1;i;i--) if(v[i] > v[i - 1])swap(v[i],v[i - 1]); } } int cal() { int ret = 0; for(int i=0;i<v.size();i++) if(ret < (ret ^ v[i])) ret ^= v[i]; return ret; } }; Base seg[maxn << 2],cur; inline void Insert(int x,int l,int r,int L,int R,int v) { //cout<<x<<endl; if(L <= l && r <= R) { seg[x].add(v); return; } int mid = (l + r) >> 1; if(L <= mid)Insert(ls,l,mid,L,R,v); if(R > mid)Insert(rs,mid + 1,r,L,R,v); } inline void solve(int x,int l,int r,Base cur) { for(int i=0;i<seg[x].v.size();i++)cur.add(seg[x].v[i]); if(l == r) { printf("%d\n",cur.cal()); return; } int mid = (l + r) >> 1; solve(ls,l,mid,cur);solve(rs,mid + 1,r,cur); } int main() { //freopen("20.in","r",stdin); n = read(); for(int i=1;i<=n;i++) { a[i] = read(); if(a[i] < 0)last[hsh[-a[i]]] = i - 1; else hsh[a[i]] = i; } for(int i=1;i<=n;i++) { if(a[i] < 0)continue; if(last[i] == 0)last[i] = n; Insert(1,1,n,i,last[i],a[i]); } solve(1,1,n,cur); }