一、题目
小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏。
每个时刻她会给小葱一颗小葱苗或者是从小葱手里拿走一颗小葱苗,并且让小葱从自己手中的小葱苗里选出一些小葱苗使得选出的小葱苗上的数字的异或和最大。
这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为Oi选手的你,你能帮帮他吗?
你只需要输出最大的异或和即可,若小葱手中没有小葱苗则输出0。
Input
第一行一个正整数n表示总时间;第二行n个整数a1,a2…an,若ai大于0代表给了小葱一颗数字为ai的小葱苗,否则代表从小葱手中拿走一颗数字为-ai的小葱苗。
Output
输出共n行,每行一个整数代表第i个时刻的最大异或和。
Note
二、解法
线性基是很难删除的,可以用线段树分治,我们求出每一个值覆盖的时间范围,把它打到线段树上,然后再跑一边线段树,这样就只需要修改了,带着线性基让下传,在时就询问。
至于求出一个覆盖的时间范围,我用的是套,详细请康代码。
#include <cstdio>
#include <vector>
#include <cstring>
#include <map>
using namespace std;
const int M = 500005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,sz,L[M],R[M],val[M];vector<int> t[4*M];
map<int,vector<int> > mp;
struct basis
{
int p[40];
basis() {memset(p,0,sizeof p);}
void ins(int x)
{
for(int i=30;i>=0;i--)
{
if(!(x>>i&1)) continue;
if(!p[i]) {p[i]=x;return;}
x^=p[i];
}
}
int ask()
{
int t=0;
for(int i=30;i>=0;i--)
if((t^p[i])>t) t^=p[i];
return t;
}
};
void ins(int i,int l,int r,int L,int R,int v)
{
if(L>r || l>R) return ;
if(L<=l && r<=R)
{
t[i].push_back(v);
return ;
}
int mid=(l+r)>>1;
ins(i<<1,l,mid,L,R,v);
ins(i<<1|1,mid+1,r,L,R,v);
}
void ask(int i,int l,int r,basis a)
{
for(int j=0;j<t[i].size();j++)
a.ins(t[i][j]);
if(l==r)
{
printf("%d\n",a.ask());
return ;
}
int mid=(l+r)>>1;
ask(i<<1,l,mid,a);
ask(i<<1|1,mid+1,r,a);
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
{
int x=read();
if(x>0)
{
mp[x].push_back(++m);
L[m]=i;val[m]=x;
}
else
{
x=-x;sz=mp[x].size()-1;
R[mp[x][sz]]=i-1;
mp[x].pop_back();
}
}
for(int i=1;i<=m;i++)
{
if(!R[i]) R[i]=n;
ins(1,1,n,L[i],R[i],val[i]);
}
basis fuck;
ask(1,1,n,fuck);
}