Description
小苗去市場上買了一捆小蔥苗,她突然一時興起,於是她在每顆小蔥苗上寫上一個數字,然後把小蔥叫過來玩遊戲。
每個時刻她會給小蔥一顆小蔥苗或者是從小蔥手裏拿走一顆小蔥苗,並且
讓小蔥從自己手中的小蔥苗裏選出一些小蔥苗使得選出的小蔥苗上的數字的異或和最大。
這種小問題對於小蔥來說當然不在話下,但是他的身邊沒有電腦,於是他打電話給同爲Oi選手的你,你能幫幫他嗎?
你只需要輸出最大的異或和即可,若小蔥手中沒有小蔥苗則輸出0。
Input
第一行一個正整數n表示總時間;第二行n個整數a1,a2...an,若ai大於0代表給了小蔥一顆數字爲ai的小蔥苗,否則代表從小蔥手中拿走一顆數字爲-ai的小蔥苗。
Output
輸出共n行,每行一個整數代表第i個時刻的最大異或和。
Sample Input
6
1 2 3 4 -2 -3
Sample Output
1
3
3
7
7
5
HINT
N<=500000,Ai<=2^31-1
題解:
最大異或和第一個想到的就是線性基。
由於線性基無法進行刪除操作,所以我們考慮離線。
我們可以以時間來建一棵線段樹,給每個線段樹的節點開一個vector,存儲這個節點所包含有哪些數。將每一次插入和刪除同一個數看做一個個的區間進行修改。注意要用到標記永久化。最後遍歷整棵線段樹,用線性基求出每一個時間的答案。具體請看代碼。
如果有誤在評論區吼一聲哦!
#include<cmath>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,tot,a[500010],lsh[500010],head[500010],nxt[500010],last[500010];
vector<int>Seg[2000010];
struct xxj{
int a[35];
xxj(){
memset(a,0,sizeof(a));
}
void insert(int x){
for(int i=30;i>=0;i--){
if(x&(1<<i)){
if(a[i]){
x^=a[i];
if(!x)
return;
}
else{
a[i]=x;
return;
}
}
}
return;
}
int getmax(){
int ans=0;
for(int i=30;i>=0;i--)
if((ans^a[i])>ans)
ans^=a[i];
return ans;
}
};
int rd(){
int x=0,y=1;
char c;
do{
c=getchar();
if(c=='-')
y=-y;
}while(!isdigit(c));
do{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}while(isdigit(c));
return x*y;
}
void update(int o,int l,int r,int L,int R,int v){
if(L<=l&&r<=R){
Seg[o].push_back(v);
return;
}
int mid=(l+r)>>1;
if(L<=mid)
update(o<<1,l,mid,L,R,v);
if(R>mid)
update(o<<1|1,mid+1,r,L,R,v);
return;
}
void Query(int o,int l,int r,xxj a){
for(int i=0;i<Seg[o].size();i++)
a.insert(Seg[o][i]);
if(l==r){
printf("%d\n",a.getmax());
return;
}
int mid=(l+r)>>1;
Query(o<<1,l,mid,a);
Query(o<<1|1,mid+1,r,a);
return;
}
int main(){
memset(Seg,NULL,sizeof(Seg));
n=rd();
for(int i=1;i<=n;i++)
lsh[i]=labs(a[i]=rd());
sort(lsh+1,lsh+n+1);
m=unique(lsh+1,lsh+n+1)-(lsh+1);
for(int i=1;i<=n;i++){
int d=lower_bound(lsh+1,lsh+m+1,labs(a[i]))-lsh;
if(a[i]>0){
if(!head[d])
head[d]=last[d]=i;
else{
nxt[last[d]]=i;
last[d]=i;
}
}
else{
update(1,1,n,head[d],i-1,-a[i]);
head[d]=nxt[head[d]];
}
}
for(int i=1;i<=m;i++){
if(lsh[i]==lsh[i-1]||!head[i])
continue;
update(1,1,n,head[i],n,lsh[i]);
}
xxj o;
Query(1,1,n,o);
return 0;
}