bzoj 4184 shallot——线段树分治+线性基
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4184
本来想了可持久化trie,不过空间是 nlogn (出一个节点的时候把 tot 复原就能做到),时间是 nlog2n 的,不太可过。
查了查发现就是线性基。因为新增一些数的话,线性基只会变大,所以可以很方便地栈序撤销。不过这样时间是不是还是 nlog2n ?
现性基求最大值是看看异或上这个位上的数,答案能否变大。能的话就异或上。
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> #define ls Ls[cr] #define rs Rs[cr] #define pb push_back using namespace std; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } const int N=5e5+5,M=N<<1,K=30; int n,tot,tp[N],Ls[M],Rs[M],b[K+5],bin[K+5]; map<int,int> mp; vector<int> vt[M],cg[M]; void build(int l,int r,int cr) { if(l==r)return; int mid=l+r>>1; ls=++tot; build(l,mid,ls); rs=++tot; build(mid+1,r,rs); } void ins(int l,int r,int cr,int L,int R,int k) { if(l>=L&&r<=R){vt[cr].pb(k);return;} int mid=l+r>>1; if(L<=mid)ins(l,mid,ls,L,R,k); if(mid<R)ins(mid+1,r,rs,L,R,k); } void ins(int k,int cr) { for(int t=K;t>=0;t--) { if(!(k&bin[t]))continue; if(b[t])k^=b[t]; else{ b[t]=k; cg[cr].pb(t); return;} } } void dfs(int cr) { if(!cr)return; int sz=vt[cr].size(); for(int i=0;i<sz;i++) ins(vt[cr][i],cr); if(!ls) { int ans=0; for(int t=K;t>=0;t--) if((ans^b[t])>ans)ans^=b[t]; printf("%d\n",ans); } else dfs(ls),dfs(rs); sz=cg[cr].size(); for(int i=0;i<sz;i++)b[cg[cr][i]]=0; } int main() { bin[0]=1;for(int i=1;i<=K;i++)bin[i]=bin[i-1]<<1; n=rdn(); tot=1;build(1,n,1); for(int i=1,d;i<=n;i++) { d=rdn(); if(d>0) mp[d]=i,tp[i]=d; else ins(1,n,1,mp[-d],i-1,-d),tp[mp[-d]]=0; } for(int i=1;i<=n;i++) if(tp[i])ins(1,n,1,i,n,tp[i]); dfs(1); return 0; }