1. 程式人生 > >[BZOJ4184]shallot(線段樹+線性基)

[BZOJ4184]shallot(線段樹+線性基)

=== ===

這裡放傳送門

=== ===

題解

線性基不支援刪除,但是可以發現每個數字出現的範圍是一段區間,那麼如果用線段樹把這一段區間打上標記,然後就相當於是每次單點查詢。也就是搞一個下標是時間的線段樹。然後標記永久化,查答案的時候dfs一遍線段樹就可以了。
這題空間賊卡。。一開始算算理論上界4*n還得加上線性基根本開不下。。那動態開點吧,nlogn還是不行。。最後乾脆出幾組大資料看看發現最多700000+個節點,然後卡著開陣列終於跑過去了。。。

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; int n,a[500010],now[40],cnt,rt,ans[500010],nxt[500010],head[500010],p[500010]; bool ext[500010]; struct segtree{ int l,r,v[32],res; segtree(){l=r=0;res=31;memset(v,0,sizeof(v));} void add(int val){ if (res==0) return; for (int i=30;i>=0;i--) if (val&(1<<i)) if
(v[i]==0){v[i]=val;--res;break;} else val^=v[i]; } int calc(){ int ans=0; for (int i=30;i>=0;i--) if ((ans^v[i])>ans) ans^=v[i]; return ans; } void add(segtree now){ if (res==0) return; for (int i=30;i>=0;i--) if
(now.v[i]!=0){ if (res==0) break; if (v[i]==0){v[i]=now.v[i];--res;continue;} for (int j=30;j>=0;j--) if ((now.v[i])&(1<<j)) if (v[j]==0){v[j]=now.v[i];--res;break;} else now.v[i]^=v[j]; } } }t[850010],b; int Abs(int x){return (x<0)?-x:x;} int comp(int x,int y){return Abs(a[x])<Abs(a[y]);} void Prepare(){ int cnt=0,v[500010]; for (int i=1;i<=n;i++) p[i]=i; sort(p+1,p+n+1,comp); for (int i=1;i<=n;i++) if (Abs(a[p[i]])==Abs(a[p[i-1]])) if (a[p[i]]<0) v[p[i]]=-cnt; else v[p[i]]=cnt; else{ ++cnt; if (a[p[i]]<0) v[p[i]]=-cnt; else v[p[i]]=cnt; } for (int i=1;i<=cnt;i++) head[i]=n+1; for (int i=n;i>=1;i--) if (v[i]>0){ nxt[i]=head[v[i]]; head[v[i]]=i; } memset(p,0,sizeof(p)); for (int i=1;i<=n;i++) if(v[i]<0){ int val=-v[i]; p[head[val]]=i; head[val]=nxt[head[val]]; } } void add(int &i,int l,int r,int left,int right,int val){ if (i==0){i=++cnt;t[i]=segtree();} if (left<=l&&right>=r){t[i].add(val);return;} int mid=(l+r)>>1; if (left<=mid) add(t[i].l,l,mid,left,right,val); if (right>mid) add(t[i].r,mid+1,r,left,right,val); } void getans(int now,int l,int r,segtree base){ segtree newbase=base; newbase.add(t[now]); if (l==r) {ans[l]=newbase.calc();return;} int mid=(l+r)>>1; getans(t[now].l,l,mid,newbase); getans(t[now].r,mid+1,r,newbase); } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&a[i]); Prepare(); cnt=rt=0; for (int i=1;i<=n;i++) if (a[i]>0) if (p[i]==0) add(rt,1,n,i,n,a[i]); else add(rt,1,n,i,p[i]-1,a[i]); getans(rt,1,n,b); for (int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }