•参考资料
[1]:在线线性基
[2]:离线线性基
[3]:离线线性基
•题意
给你 n 个数,m 次询问;
每次询问给定一个区间 $l,r$,求 $a_{l \cdots r}$ 异或的最大值;
•线段树+线性基
参考了一下资料[1],学会了如何将线性基和线段树结合;
虽然在此题中会 TLE,但是却学到了不少东西;
首先,在建树的时候,将叶节点上的值插入到线性基中;
在回溯的时候,通过 Merge 操作,将 pos 的儿子节点的线性基合并到 pos 的线性基上;
类似于常规线段树中的 pushUp 操作;
此算法可以用来做这道题:洛谷P4839
•Code(线段树TLE版本)
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ls(x) (x<<1) 4 #define rs(x) (x<<1|1) 5 const int maxn=5e5+50; 6 7 int n,q; 8 int a[maxn]; 9 struct Seg 10 { 11 int l,r; 12 int a[25]; 13 int mid(){return l+((r-l)>>1);} 14 void Insert(int x) 15 { 16 for(int i=20;i >= 0;--i) 17 { 18 if(x&(1<<i)) 19 { 20 if(!a[i]) 21 { 22 a[i]=x; 23 return ; 24 } 25 x ^= a[i]; 26 } 27 } 28 } 29 int Max() 30 { 31 int ans=0; 32 for(int i=20;i >= 0;--i) 33 ans=max(ans,ans^a[i]); 34 return ans; 35 } 36 }seg[maxn<<2]; 37 38 Seg Marge(Seg a,Seg b) 39 { 40 Seg tmp=b; 41 for(int i=0;i <= 20;++i) 42 if(a.a[i]) 43 tmp.Insert(a.a[i]); 44 return tmp; 45 } 46 void buildSeg(int l,int r,int pos) 47 { 48 seg[pos].l=l; 49 seg[pos].r=r; 50 51 if(l == r) 52 { 53 seg[pos].Insert(a[l]); 54 return ; 55 } 56 57 int mid=l+((r-l)>>1); 58 buildSeg(l,mid,ls(pos)); 59 buildSeg(mid+1,r,rs(pos)); 60 61 seg[pos]=Marge(seg[ls(pos)],seg[rs(pos)]); 62 seg[pos].l=l;///此处要注意,因为Marge返回的结果未给l,r赋值 63 seg[pos].r=r; 64 } 65 Seg Query(int l,int r,int pos) 66 { 67 if(seg[pos].l == l && seg[pos].r == r) 68 return seg[pos]; 69 70 int mid=seg[pos].mid(); 71 72 if(r <= mid) 73 return Query(l,r,ls(pos)); 74 else if(l > mid) 75 return Query(l,r,rs(pos)); 76 else 77 return Marge(Query(l,mid,ls(pos)),Query(mid+1,r,rs(pos))); 78 } 79 void Solve() 80 { 81 for(int i=1;i <= q;++i) 82 { 83 int l,r; 84 scanf("%d%d",&l,&r); 85 86 Seg ans=Query(l,r,1); 87 88 printf("%d\n",ans.Max()); 89 } 90 } 91 int main() 92 { 93 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 94 scanf("%d",&n); 95 for(int i=1;i <= n;++i) 96 scanf("%d",a+i); 97 buildSeg(1,n,1); 98 99 scanf("%d",&q); 100 Solve(); 101 102 return 0; 103 }