如果没有修改,这个题就是个线性基板子题对吧。
再看加上修改之后怎么整。
我们发现,对于任意一种已经确定数字的情况,只要线性基建好了,答案可以搞出来。
那么问题就是怎么动态维护线性基。
啥?动态维护??不存在的!我才不告诉你我不会写那玩意
因为只有删除操作,所以顺序颠倒就是一个一个加入数字。
也就是离线然后一个一个插入线性基。
这样就搞定了,复杂度也就。
再看那个区间怎么整。
由于区间具有连续性,所以我们可以考虑用并查集来搞事。
每次假如一个数,如果这个数左或者右边有存在的区间,那就合并并查集,并且暴力合并线性基。
答案就是前一个询问的答案与当前数字对应答案取最大值。
附代码:
#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;
}
京公网安备 11010502036488号