题目地址:https://codeforces.com/contest/1100/problem/F
题目:
多次查询区间的最大异或值,但是数据范围比较大,5e5个数,5e5个查询
解题思路:
用线段树维护区间线性基,果然T了,T在第19个test
感觉这道题其实和https://blog.csdn.net/Cassie_zkq/article/details/96448531的做法有点类似,对于区间查询都是先离线处理,然后区间的右边界一定,依次寻找答案
参考网上的代码,这道题可以不用对右边界排序,存储方法比较巧妙。
对于每个行阶梯矩阵的每一行,采用后入为主的思想,如果j行已经有数了,那么就让新的数取代原来的数,让新的数和原来的数异或,之后再向后位查询可以放置的位置,并记录行阶梯矩阵每行的pos值,即若该行的值是由a[i],a[k]..a[m]异或出来的,让pos=最小的下标。
在右边界一定的前提下,统计每个区间的最大异或值
ac代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5;
const int max_base = 20;
int n, q, l, r;
int a[maxn], val[max_base+3], pos[max_base+3], ans[maxn];
vector<pair<int, int> > R[1000005];//R[i]存右边界为i的区间,key表示左边界,value表示对应的编号
int main()
{
//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
cin >> q;
for(int i = 1; i <= q; i++)
{
scanf("%d %d", &l, &r);
R[r].push_back(make_pair(l, i));
}
for(int i = 1; i <= n; i++)//右边界为i
{
int x = a[i], p = i;
for(int j = max_base; j >= 0 ;j--)
{
if(x>>j&1)
{
if(!val[j])//填入
{
val[j] = x;
pos[j] = p;
break;
}
if(pos[j] < p) swap(val[j], x), swap(pos[j], p);
x ^= val[j];
}
}
for(int j = 0; j < R[i].size(); j++)
{
for(int k = max_base; k >= 0; k--)
if(R[i][j].first <= pos[k] && val[k])
ans[R[i][j].second] = max(ans[R[i][j].second], ans[R[i][j].second]^val[k]);
}
}
for(int i = 1; i <= q; i++)
cout << ans[i] << endl;
return 0;
}