BZOJ 4184 shallot 线性基+分治
Description
小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏。
每个时刻她会给小葱一颗小葱苗或者是从小葱手里拿走一颗小葱苗,并且让小葱从自己手中的小葱苗里选出一些小葱苗使得选出的小葱苗上的数字的异或和最大。这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为Oi选手的你,你能帮帮他吗?
Input
第一行一个正整数n表示总时间;第二行n个整数a1,a2...an,若ai大于0代表给了小葱一颗数字为ai的小葱苗,否则代表从小葱手中拿走一颗数字为-ai的小葱苗。
Output
输出共n行,每行一个整数代表第i个时刻的最大异或和。
Sample Input
1 2 3 4 -2 -3
Sample Output
3
3
7
7
5
HINT
N<=500000,Ai<=2^31-1
—————————————————————————————————————————————————————
题意概述:
维护一个可重集合,进行N次操作,每次向集合中插入一个数字或者从集合中删除一个数字,并回答当前集合中的数字能够形成的最大亦或和。
分析:
线性基只能插入不能删除,所以我们只能把删除的影响处理掉,即不删除来搞事情。
可以发现一个数字在一个时间区间内出现,把每个数字的出现和消失当成一个事件。对于一个时间区间,区间右端点的答案只会被在这个区间中开始但是还没有结束的事件或者开始和结束横跨这个区间的操作所影响。
于是可以采用分治的方法,对于当前区间,横跨整个区间的操作显然对这个区间的子区间也会有影响,直接修改。否则:事件在左半边的时候丢给左半边递归处理,事件在右半边的时候丢给右半边递归处理,事件跨越分界线的时候分成两个事件分别丢给左右区间。
因为是模拟线段树的分法,所以一个区间至多被分成logn个区间,空间显然也是可以承受的。
%%%PoPoQQQ大爷ORZ
时间复杂度O(NlogNloga)。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<cctype> 12 using namespace std; 13 const int maxn=500005; 14 15 int N,ans[maxn]; 16 struct data{ int l,r,v; }; 17 map<int,int>C,lp; 18 map<int,int>::iterator it; 19 struct Linear_Base{ 20 static const int up=31; 21 int b[up]; 22 Linear_Base(){ memset(b,0,sizeof(b)); } 23 void ins(int x){ 24 for(int i=up-1;i>=0;i--) if((1<<i)&x){ 25 if(!b[i]) { b[i]=x; break; } 26 else x^=b[i]; 27 } 28 } 29 int query(){ 30 int re=0; 31 for(int i=up-1;i>=0;i--) 32 re=max(re,re^b[i]); 33 return re; 34 } 35 }Lb; 36 37 void solve(int L,int R,vector<data>a,Linear_Base bl) 38 { 39 int m=L+R>>1,n=a.size(); 40 vector<data>l,r; 41 for(int i=0;i<n;i++){ 42 if(a[i].l==L&&a[i].r==R) bl.ins(a[i].v); 43 else if(a[i].r<=m) l.push_back(a[i]); 44 else if(a[i].l>m) r.push_back(a[i]); 45 else{ 46 l.push_back((data){a[i].l,m,a[i].v}); 47 r.push_back((data){m+1,a[i].r,a[i].v}); 48 } 49 } 50 if(L==R){ ans[L]=bl.query(); return; } 51 solve(L,m,l,bl); 52 solve(m+1,R,r,bl); 53 } 54 void work() 55 { 56 scanf("%d",&N); 57 vector<data>a; 58 int x; 59 for(int i=1;i<=N;i++){ 60 scanf("%d",&x); 61 if(x<0&&--C[-x]==0) a.push_back((data){lp[-x],i-1,-x}),C.erase(-x),lp.erase(-x); 62 else if(x>0&&++C[x]==1) lp[x]=i; 63 } 64 for(it=C.begin();it!=C.end();it++) 65 a.push_back((data){lp[it->first],N,it->first}); 66 C.clear(); lp.clear(); 67 solve(1,N,a,Lb); 68 for(int i=1;i<=N;i++) printf("%d\n",ans[i]); 69 } 70 int main() 71 { 72 work(); 73 return 0; 74 }