題意:給定長度爲n的數列和m次操做, 每次在數列末尾添加一個數或者詢問區間L到R的子集異或和最大值, 強制在線。 \(n, m\leq 5 \times 10^{5}\)php
解法:對全部\(i\epsilon (1, n)\)維護一個\((1,i)\)的線性基\(a[i][32]\), 相似於前綴和的思想, 同時對每一個線性基記錄一下它每一位最後被插入的位置\(pos[i][32]\)(因而線性基的insert函數就要稍微改一下), 這樣在查詢\((L, R)\)區間的時候只有\(a[R]\)中pos大於等於\(L\)的位會對\((L, R)\)區間有貢獻。node
P.S. 若是沒有強制在線那麼對區間按右端點排序後只須要維護一個線性基就能夠了。c++
P.S.S. 瓜神教會了我前綴線性基 orz函數
代碼:spa
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 5; int n, m; struct node{ int p[32], pos[32]; }a[maxn]; void ins(int x) { n++; a[n] = a[n - 1]; int pos = n; for(int i = 31; i >= 0; i--) { if(x & (1 << i)) { if(!a[n].p[i]) { a[n].p[i] = x; a[n].pos[i] = pos; return; } if(a[n].pos[i] < pos) { swap(a[n].pos[i], pos); swap(a[n].p[i], x); } x ^= a[n].p[i]; } } } int qmax(int l, int r) { int res = 0; for(int i = 31; i >= 0; i--) { if(a[r].pos[i] < l) continue; if((a[r].p[i] ^ res)> res) res ^= a[r].p[i]; } return res; } int main() { int T; cin >> T; memset(a[0].p, 0, sizeof(a[0].p)); memset(a[0].pos, 0, sizeof(a[0].pos)); while(T--) { scanf("%d%d", &n, &m); int tmp = n; n = 0; for(int i = 1; i <= tmp; i++) { int x; scanf("%d", &x); ins(x); } int las = 0; while(m--) { int f; scanf("%d", &f); if(f) { int x; scanf("%d", &x); x ^= las; ins(x); } else{ int l, r; scanf("%d%d", &l, &r); l = (l ^ las) % n + 1; r = (r ^ las) % n + 1; if(l > r) swap(l, r); //cout << l << " " << r << '\n'; las = qmax(l, r); printf("%d\n", las); } } } return 0; }