BZOJ 4184 shallot
好神的一道题目
某只萌萌哒神犇给我安利了一发
首先如果没有删除,我们会做,因为这是裸的线性基
那么对于任意的时间,我们只需要知道有多少个数且这些数是什么就可以维护线性基了
我们考虑对时间搞出一颗线段树
对于任意的数,其存在的时间是一段区间,那么我们就可以在线段树上做区间覆盖
可以证明,在打标记的情况下,最多被分解为log(n)个区间
那么我们只需要O(nlog(n))的空间就可以记录每个时间上面的数是什么了
最后对线段树做一遍DFS,在过程中动态维护线性基就可以知道答案了
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #include<set> #include<vector> using namespace std; const int maxn=2000010; int n,x; set<pair<int,int> >S; vector<int>V[maxn]; int L[maxn],R[maxn],mid[maxn]; struct Ans{ int Num[32]; Ans(){memset(Num,0,sizeof(Num));} void push(int v){ for(int i=30;i>=0;--i){ if(v>>i&1){ if(!Num[i]){Num[i]=v;break;} else{v^=Num[i];} } }return; } int ask(){ int ans=0; for(int i=30;i>=0;--i){ if((ans^Num[i])>ans)ans^=Num[i]; }return ans; } }; void build(int o,int l,int r){ L[o]=l;R[o]=r; if(l==r)return; mid[o]=(l+r)>>1; build(o<<1,L[o],mid[o]); build(o<<1|1,mid[o]+1,R[o]); } void Get_modify(int o,int x,int y,int v){ if(L[o]>=x&&R[o]<=y){V[o].push_back(v);return;} if(y<=mid[o])Get_modify(o<<1,x,y,v); else if(x>mid[o])Get_modify(o<<1|1,x,y,v); else {Get_modify(o<<1,x,y,v);Get_modify(o<<1|1,x,y,v);} } void Get_ans(int o,Ans now){ int sz=V[o].size(); for(int i=0;i<sz;++i)now.push(V[o][i]); if(L[o]==R[o]){printf("%d\n",now.ask());return;} Get_ans(o<<1,now);Get_ans(o<<1|1,now); } int main(){ scanf("%d",&n);build(1,1,n); for(int i=1;i<=n;++i){ scanf("%d",&x); if(x==0)continue; if(x>0)S.insert(make_pair(x,i)); else{ pair<int,int> p=*S.lower_bound(make_pair(-x,-1)); S.erase(p);Get_modify(1,p.second,i-1,-x); } } set<pair<int,int> >::iterator it; for(it=S.begin();it!=S.end();it++)Get_modify(1,(*it).second,n,(*it).first); Get_ans(1,Ans()); return 0; }