题意:给你n个数字,n个消除位置的顺序,问每次消除前不包含无效位置的区间的异或和的最大值。
题解:我们反向加入数字,那么每次会和pos-1与pos+1的区间合并,我们通过线性基记录每个位置的情况,通过并查集合并,查询合并完的线性基的最大异或和,就可以了。
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int per[maxn];
int p[maxn];
int ans[maxn];
int mark[maxn];
struct L_B{
int d[35];
L_B()
{
memset(d,0,sizeof(d));
}
bool insert(int val)
{
for(int i=30;i>=0;i--)
{
if(val&(1<<i))
{
if(!d[i])
{
d[i]=val;
break;
}
val^=d[i];
}
}
return val>0;
}
int query_max()
{
int ret=0;
for(int i=30;i>=0;i--)
{
if((ret^d[i])>ret)
{
ret^=d[i];
}
}
return ret;
}
}a[maxn];
L_B merge(const L_B &n1,const L_B &n2)// a[nx]=merge(a[nx],a[ny]);
{
L_B ret=n1;
for(int i=30;i>=0;i--)
{
if(n2.d[i])
ret.insert(n2.d[i]);
}
return ret;
}
int find(int x)
{
if(x==per[x])
{
return x;
}
return per[x]=find(per[x]);
}
int link(int x,int y)
{
int nx=find(x),ny=find(y);
if(nx!=ny)
{
per[ny]=nx; // ny的父节点是nx
}
a[nx]=merge(a[nx],a[ny]);// 维护左边的线性基础
return a[nx].query_max();
}
int main()
{
L_B();
memset(mark,0,sizeof(mark));
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int w;
cin>>w;
a[i].insert(w);
per[i]=i;
}
for(int i=1;i<=n;i++)
{
cin>>p[i];
}
int sum=0;
for(int i=n;i>=1;i--)
{
int k=p[i];
mark[k]=1;
sum=max(a[k].query_max(),sum);
if(mark[k-1])
{
sum=max(sum,link(k-1,k));
}
if(mark[k+1])
{
sum=max(sum,link(k,k+1));
}
ans[i]=sum;
}
for(int i=1;i<=n;i++)
{
cout<<ans[i]<<endl;
}
return 0;
}