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;

}

  

你可能感兴趣的:(sha)