Chip Factory(字典树,学会将路暂时删除)

来源:互联网 发布:小米换苹果 迁移数据 编辑:程序博客网 时间:2024/06/04 01:10

题目链接:Chip Factory

题目大意:给你n个数,从中选出三个数a,b,c,使得(a+b)异或c最大。

思路:先建立字典树,选出两个数,先暂时删除,然后找出与其异或的最大值。

下面是代码:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;const int maxn=1009;int sum,coun;struct node{    int l,r;//左(右)节点位置    int sum_l,sum_r;//记录有多少个数是从这个节点的左(右)经过    int inq;//最终这个数是几。} dis[100*maxn];int a[maxn],wei[33];void build(int x)//建立字典树{    int now=0;    for(int i=30; i>=0; i--)    {        if(wei[i]&x)        {            if(dis[now].r==-1)            {                dis[coun].inq=dis[coun].sum_r=dis[coun].sum_l=0;                dis[coun].r=dis[coun].l=-1;                dis[now].r=coun++;            }            dis[now].sum_r++;            now=dis[now].r;        }        else        {            if(dis[now].l==-1)            {                dis[coun].inq=dis[coun].sum_r=dis[coun].sum_l=0;                dis[coun].l=dis[coun].r=-1;                dis[now].l=coun++;            }            dis[now].sum_l++;            now=dis[now].l;        }    }    dis[now].inq=x;}int dele(int x)//暂时删除a[i](a[j]){    int now=0;    for(int i=30; i>=0; i--)    {        if(wei[i]&x)        {            dis[now].sum_r--;            if(dis[now].sum_r==0)//没有数从这里通过,说明只有x这个数会经过这里,返回此处的位置            {                int f=dis[now].r;                dis[now].r=-1;                return f;            }            now=dis[now].r;        }        else        {            dis[now].sum_l--;            if(dis[now].sum_l==0)            {                int f=dis[now].l;                dis[now].l=-1;                return f;            }            now=dis[now].l;        }    }}int match(int x)//查找与(a[i]+a[j])异或的最大值{    int now=0;    for(int i=30; i>=0; i--)    {        if(((wei[i]&x)&&dis[now].l!=-1)||dis[now].r==-1)            now=dis[now].l;        else now=dis[now].r;    }    return dis[now].inq;}void restore(int x,int f)//回复a[i](a[j])这个数{    int now=0;    for(int i=30; i>=0; i--)    {        if(wei[i]&x)        {            dis[now].sum_r++;            if(dis[now].r==-1)            {                dis[now].r=f;                return ;            }            now=dis[now].r;        }        else        {            dis[now].sum_l++;            if(dis[now].l==-1)            {                dis[now].l=f;                return ;            }            now=dis[now].l;        }    }}int main(){    int t;    wei[0]=1;    for(int i=1; i<31; i++)        wei[i]=wei[i-1]*2;    scanf("%d",&t);    while(t--)    {        int n;        scanf("%d",&n);        sum=0,coun=1;        dis[0].l=dis[0].r=-1;        dis[0].inq=0;        dis[0].sum_l=dis[0].sum_r=0;        for(int i=0; i<n; i++)        {            scanf("%d",&a[i]);            build(a[i]);//建立字典树        }        for(int i=0; i<n; i++)//遍历所有的情况(a[i]+a[j])        {            int x=dele(a[i]);//先删除,a[i],x代表a[i]这个节点的位置            for(int j=i+1; j<n; j++)            {                int y=dele(a[j]);//删除,a[j],y代表a[j]这个节点的位置                int f=match(a[i]+a[j]);                sum=max(sum,f^(a[i]+a[j]));                restore(a[j],y);//还原a[j],还原是有先后顺序的,一定是先还原a[j],再还原a[i]            }            restore(a[i],x);//还原a[i]        }        printf("%d\n",sum);    }    return 0;}