自己犯了一个shab错误结果debug半小时。。
题意:n个数,要你从这n个数中分别找两个区间,使得区间内的数异或值最大和最小。
思路:字典树异或裸题,以前没做过这种同时求最大最小值的,于是板子来了一发。
把每个数的前缀异或和扔进字典树,然后查找只需扫一遍过去,先把当前值的前缀异或和从字典树中删去,然后查找最小值只需将当前位置的前缀异或和的二进制直接查找下去,而查询最大值则需要把二进制翻转,然后沿着字典树走下去,如果为1,说明有贡献,加上即可。
注意返回的都只是这n个前缀异或除去当前位的某一个。在开始插入之间先将0插入字典树中。
动态字典树:
const int N=50000+10;
int cnt,n,a[35];
ll sum[N];
struct tree
{
int f;
tree *next[2];
tree()
{
next[0]=next[1]=NULL;
f=0;
}
};
//tree mem[N*40];
void ch(ll x)
{
memset(a,0,sizeof(a));
int len=0;
while(x) a[len++]=(x&1),x/=2;
}
void insert(tree *root,ll x)
{
ch(x);
int len=32;
tree *p=root;
while(len>=0)
{
int id=a[len];
if(p->next[id]==NULL) p->next[id]=new tree();
p=p->next[id];
p->f++;
len--;
}
}
ll find(tree *root)
{
tree *p=root;
int len=32;
ll ans=0;
while(len>=0)
{
int id=a[len];
if(p->next[id]==NULL||p->next[id]->f==0) id^=1;
p=p->next[id];
if(id) ans+=ll(1)<<len;
len--;
}
return ans;
}
void del(tree *root)
{
tree *p=root;
int len=32;
while(len>=0)
{
int id=a[len];
p=p->next[id];
p->f--;
len--;
}
}
void dele(tree *root)
{
for(int i=0; i<2; i++)
if(root->next[i]) dele(root->next[i]);
delete(root);
}
int main()
{
int t,x;
scanf("%d",&t);
int t1=t;
while(t--)
{
scanf("%d",&n);
// memset(mem,0,sizeof(mem));
cnt=sum[0]=0;
tree *root=new tree();
insert(root,sum[0]);
for(int i=1; i<=n; i++)
{
scanf("%d",&x);
sum[i]=sum[i-1]^x;
insert(root,sum[i]);
}
ll ma=0,mi=INF;
for(int i=1; i<=n; i++)
{
ch(sum[i]);
del(root);
mi=min(mi,sum[i]^find(root));
for(int j=0; j<33; j++) a[j]^=1;
ma=max(ma,sum[i]^find(root));
insert(root,sum[i]);
}
printf("Case %d: %lld %lld\n",t1-t,ma,mi);
dele(root);
}
return 0;
}
静态字典树:
const int N=50000+10;
int cnt,n,a[35];
ll sum[N];
struct tree
{
int f;
tree *next[2];
};
tree mem[N*40];
void ch(ll x)
{
memset(a,0,sizeof(a));
int len=0;
while(x) a[len++]=(x&1),x/=2;
}
void insert(tree *root,ll x)
{
ch(x);
int len=32;
tree *p=root;
while(len>=0)
{
int id=a[len];
if(p->next[id]==NULL) p->next[id]=&mem[cnt++];
p=p->next[id];
p->f++;
len--;
}
}
ll find(tree *root)
{
tree *p=root;
int len=32;
ll ans=0;
while(len>=0)
{
int id=a[len];
if(p->next[id]==NULL||p->next[id]->f==0) id^=1;
p=p->next[id];
if(id) ans+=ll(1)<<len;
len--;
}
return ans;
}
void del(tree *root)
{
tree *p=root;
int len=32;
while(len>=0)
{
int id=a[len];
p=p->next[id];
p->f--;
len--;
}
}
int main()
{
int t,x;
scanf("%d",&t);
int t1=t;
while(t--)
{
scanf("%d",&n);
cnt=sum[0]=0;
memset(mem,0,sizeof(mem));
tree *root=&mem[cnt++];
insert(root,sum[0]);
for(int i=1; i<=n; i++)
{
scanf("%d",&x);
sum[i]=sum[i-1]^x;
insert(root,sum[i]);
}
ll ma=0,mi=INF;
for(int i=1; i<=n; i++)
{
ch(sum[i]);
del(root);
mi=min(mi,sum[i]^find(root));
for(int j=0; j<33; j++) a[j]^=1;
ma=max(ma,sum[i]^find(root));
insert(root,sum[i]);
}
printf("Case %d: %lld %lld\n",t1-t,ma,mi);
}
return 0;
}