如果没有修改,这个题就是个线性基板子题对吧。
再看加上修改之后怎么整。
我们发现,对于任意一种已经确定数字的情况,只要线性基建好了,答案可以搞出来。
那么问题就是怎么动态维护线性基。
啥?动态维护??不存在的!我才不告诉你我不会写那玩意
因为只有删除操作,所以顺序颠倒就是一个一个加入数字。
也就是离线然后一个一个插入线性基。
这样就搞定了,复杂度也就。
再看那个区间怎么整。
由于区间具有连续性,所以我们可以考虑用并查集来搞事。
每次假如一个数,如果这个数左或者右边有存在的区间,那就合并并查集,并且暴力合并线性基。
答案就是前一个询问的答案与当前数字对应答案取最大值。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 100010 #define MAXM 64 using namespace std; int n,pos[MAXN],fa[MAXN]; long long val[MAXN],ans[MAXN]; struct Linear_Basis{ long long base[MAXM]; bool flag_zero; void init(){ flag_zero=false; for(int i=0;i<=62;i++)base[i]=0; } void insert(long long x){ for(int i=62;~i;i--)if(x&(1LL<<i)){ if(!base[i]){base[i]=x;return;} else x^=base[i]; } flag_zero=true; } friend Linear_Basis operator +(const Linear_Basis u,const Linear_Basis v){ Linear_Basis ret; ret.init(); for(int i=62;~i;i--){ if(u.base[i])ret.insert(u.base[i]); if(v.base[i])ret.insert(v.base[i]); } ret.flag_zero=u.flag_zero|v.flag_zero; return ret; } long long query_max(long long s){ for(int i=62;~i;i--)s=max(s,s^base[i]); return s; } }a[MAXN]; char tp[100000],*p1=tp,*p2=tp; inline char get_char(){ return p1==p2&&(p2=(p1=tp)+fread(tp,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=get_char();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=get_char();} return date*w; } int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void uniun(int x,int y){ x=find(x);y=find(y); if(x!=y){ fa[y]=x; a[x]=a[x]+a[y]; } } void work(){ for(int i=n;i>=1;i--){ fa[pos[i]]=pos[i]; a[pos[i]].init(); a[pos[i]].insert(val[pos[i]]); if(fa[pos[i]+1])uniun(pos[i],pos[i]+1); if(fa[pos[i]-1])uniun(pos[i],pos[i]-1); ans[i]=max(ans[i+1],a[pos[i]].query_max(0)); } for(int i=1;i<=n;i++)printf("%lld\n",ans[i]); } void init(){ n=read(); for(int i=1;i<=n;i++)val[i]=read(); for(int i=1;i<=n;i++){ pos[i]=read(); fa[i]=0; } } int main(){ init(); work(); return 0; }