BZOJ 4184 shallot 線性基+分治
Description
小苗去市場上買了一捆小蔥苗,她突然一時興起,於是她在每顆小蔥苗上寫上一個數字,然後把小蔥叫過來玩遊戲。
每個時刻她會給小蔥一顆小蔥苗或者是從小蔥手裏拿走一顆小蔥苗,並且讓小蔥從自己手中的小蔥苗裏選出一些小蔥苗使得選出的小蔥苗上的數字的異或和最大。這種小問題對於小蔥來說當然不在話下,但是他的身邊沒有電腦,於是他打電話給同為Oi選手的你,你能幫幫他嗎?
你只需要輸出最大的異或和即可,若小蔥手中沒有小蔥苗則輸出0。Input
第一行一個正整數n表示總時間;第二行n個整數a1,a2...an,若ai大於0代表給了小蔥一顆數字為ai的小蔥苗,否則代表從小蔥手中拿走一顆數字為-ai的小蔥苗。
Output
輸出共n行,每行一個整數代表第i個時刻的最大異或和。
Sample Input
61 2 3 4 -2 -3
Sample Output
13
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 }
BZOJ 4184 shallot 線性基+分治