[分治线段树 & 线性基] BZOJ4184: shallot

明显的分支线段树加线性基
我刚开始每个节点都开了个线性基,内存是满的 O(nlogm) O ( n log ⁡ m ) ,被卡了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>

using namespace std;

const int N=500010;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(); x=0; int f=1;
  for(;c>'9'||c<'0';c=nc())if(c=='-') f=-f;
  for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc()); x*=f;
}

int n,a[N],b[N],cnt[N],bg[N];

struct lbase{
  int a[35];
  lbase(){ memset(a,0,sizeof(a)); }

  void Add(int x){
    for(int i=31;~i;i--){
      if(!((x>>i)&1)) continue;
      if(!a[i]){
    a[i]=x; break;
      }
      x^=a[i];
    }
  }

  friend lbase operator +(lbase a,lbase b){
    for(int i=0;i<=31;i++){
      int x=b.a[i];
      if(!x) continue;
      for(int j=i;~j;j--){
    if(!((x>>j)&1)) continue;
    if(!a.a[j]){
      a.a[j]=x; break;
    }
    x^=a.a[j];
      }
    }
    return a;
  }

  int Max(){
    int ret=0;
    for(int i=31;~i;i--){
      if(ret>>i&1) continue;
      ret^=a[i];
    }
    return ret;
  }
};

void PutAns(int x){
  if(x>=10) PutAns(x/10); putchar(x%10+'0');
}

vector<int> opt[N<<2];

int ans[N];

void Add(int g,int l,int r,int L,int R,int x){
  if(l==L && r==R) return opt[g].push_back(x);
  int mid=L+R>>1;
  if(r<=mid) Add(g<<1,l,r,L,mid,x);
  else if(l>mid) Add(g<<1|1,l,r,mid+1,R,x);
  else Add(g<<1,l,mid,L,mid,x),Add(g<<1|1,mid+1,r,mid+1,R,x);
}

void Query(int g,int l,int r,lbase a){
  for(vector<int>::iterator it=opt[g].begin();it!=opt[g].end();it++) a.Add(*it);
  if(l==r) return ans[l]=a.Max(),void();
  int mid=l+r>>1;
  Query(g<<1,l,mid,a); Query(g<<1|1,mid+1,r,a);
}

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  read(n);
  for(int i=1;i<=n;i++)
    read(a[i]),b[i]=a[i]<0?-a[i]:a[i];
  int t=n;
  sort(b+1,b+1+t); t=unique(b+1,b+1+t)-b-1;
  for(int i=1;i<=n;i++){
    if(a[i]>0)
      a[i]=lower_bound(b+1,b+1+t,a[i])-b;
    else
      a[i]=-(lower_bound(b+1,b+1+t,-a[i])-b);
  }
  for(int i=1;i<=n;i++){
    if(a[i]>0){
      if(!cnt[a[i]]) bg[a[i]]=i;
      cnt[a[i]]++;
    }
    else{
      cnt[-a[i]]--;
      if(!cnt[-a[i]]) Add(1,bg[-a[i]],i-1,1,n,b[-a[i]]);
    }
  }
  for(int i=1;i<=t;i++)
    if(cnt[i]) Add(1,bg[i],n,1,n,b[i]);
  Query(1,1,n,lbase());
  for(int i=1;i<=n;i++)
    PutAns(ans[i]),putchar('\n');
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值