BZOJ4184 : shallot

考虑离线求出每个数存在的区间,用时间线段树套链表维护每段区间内存在的数字。

然后从线段树根节点开始dfs,子节点的线性基=往父节点的线性基中插入子节点存在的数字后得到的线性基。

时间复杂度$O(31n\log n)$。

 

#include<cstdio>
#include<map>
std::map<int,int>vis,loc;
inline void read(int&a){
  char c;bool f=0;a=0;
  while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
  if(c!='-')a=c-'0';else f=1;
  while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
  if(f)a=-a;
}
inline void up(int&a,int b){if(a<b)a=b;}
struct Base{
  int a[31];
  Base(){for(int i=0;i<31;i++)a[i]=0;}
  inline void ins(int x){for(int i=30;~i;i--)if(x>>i&1){if(a[i])x^=a[i];else{a[i]=x;break;}}}
  inline void ask(){
    int t=0;
    for(int i=30;~i;i--)up(t,t^a[i]);
    printf("%d\n",t);
  }
};
int n,i,x,c,d,v;
struct E{int v;E*nxt;}*g[1048577],pool[8000000],*cur=pool,*p;
void ins(int x,int a,int b){
  if(c<=a&&b<=d){p=cur++;p->v=v;p->nxt=g[x];g[x]=p;return;}
  int mid=(a+b)>>1;
  if(c<=mid)ins(x<<1,a,mid);
  if(d>mid)ins(x<<1|1,mid+1,b);
}
void dfs(int x,int a,int b,Base c){
  for(p=g[x];p;p=p->nxt)c.ins(p->v);
  if(a==b){c.ask();return;}
  int mid=(a+b)>>1;
  dfs(x<<1,a,mid,c),dfs(x<<1|1,mid+1,b,c);
}
int main(){
  for(read(n),i=1;i<=n;i++){
    read(x);
    if(x>0){if(!(vis[x]++))loc[x]=i;}
    else{if(!(--vis[-x]))c=loc[-x],d=i-1,v=-x,ins(1,1,n);}
  }
  for(std::map<int,int>::iterator j=vis.begin();j!=vis.end();j++)if(j->second)c=loc[j->first],d=n,v=j->first,ins(1,1,n);
  return dfs(1,1,n,Base()),0;
}

  

posted @ 2015-07-12 14:45  Claris  阅读(938)  评论(0编辑  收藏  举报