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;
}

 

posted on 2019-02-26 08:23  Narh  阅读(176)  评论(0编辑  收藏  举报

导航