区间异或和异或区间最大值异或区间最小值

区间异或和异或区间最大值异或区间最小值

关键

分治思想。
也可以选择固定左端点,然后选择右端点

代码

#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int M=1e5+5;

int ch[M*32][2],cnt[M*32],tot;

void init() {
    for(int i=0;i<=tot;i++)
        cnt[i]=ch[i][0]=ch[i][1]=0;
    tot=0;
}

void insert(int x) {
    int p=0;
    for(int i=30;i>=0;i--) {
        int v=x>>i&1;
        if(ch[p][v]==0)ch[p][v]=++tot;
        p=ch[p][v];
        cnt[p]++;
    }
}

void del(int x) {
    int p=0;
    for(int i=30;i>=0;i--) {
        int v=x>>i&1;
        p=ch[p][v];
        cnt[p]--;
    }
}

int ans;
void query(int x) {
    int p=0,res=0;
    for(int i=30;i>=0;i--) {
        int v=x>>i&1;
        if(cnt[ch[p][v^1]])res|=1<<i,p=ch[p][v^1];
        else p=ch[p][v];
    }
    ans=max(ans,res);
}

int a[M],b[M],sum[M];
void solve(int l,int r) {
    if(l==r)return ;
    int mid=(l+r)/2;
    solve(l,mid);
    solve(mid+1,r);
    b[mid]=sum[mid]=0;
    for(int i=mid+1;i<=r;i++)b[i]=max(b[i-1],a[i]),sum[i]=sum[i-1]^a[i];
    {
        init();
        int rp=mid;
        int mx=0,mn=inf,tmp=0;
        for(int i=mid;i>=l;i--) {
            mx=max(mx,a[i]);
            mn=min(mn,a[i]);
            tmp^=a[i];
            while(rp<r&&a[rp+1]<=mx&&a[rp+1]>=mn)insert(sum[++rp]);//最大值和最小值都在左边
            query(tmp^mx^mn);
        }
        {
            init();
            int lp=mid+1,rp=mid;
            int mx=0,mn=inf,tmp=0;
            for(int i=mid;i>=l;i--) {
                mx=max(mx,a[i]);
                mn=min(mn,a[i]);
                tmp^=a[i];
                while(rp<r&&a[rp+1]>=mn)insert(sum[rp+1]^b[rp+1]),rp++;//
                while(lp<=rp&&b[lp]<mx)del(sum[lp]^b[lp]),lp++;
                query(mn^tmp);//最小值在左边
            }
        }
    }
}

int main() {
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i],ans=max(ans,a[i]);
    solve(1,n);
    reverse(a+1,a+1+n);
    solve(1,n);
    cout<<ans;
    return 0;
}
//分治的思想,不是很懂呀
posted @ 2023-01-14 20:49  basicecho  阅读(208)  评论(0)    收藏  举报