牛客OI月赛12-提高组 C. 区间异或和异或区间最大值异或区间最小值(分治+字典树)

题目链接题目大意给你n个数,对于一个区间[l,r],xorsum=这个区间所有异或和,min = 区间最小值,max = 区间最大值,要求xorsum ^ min ^ max最大。解题思路对于xor最大,我们一般会往两个方向想:一.线性基 二.01字典树这题是用字典树。如果只是求xorsum最大,我们可以维护一个前缀异或和的字典树,然后每次得到新的前缀异或和,先在字典树查一下能得到的最大...
摘要由CSDN通过智能技术生成

题目链接

题目大意

给你n个数,对于一个区间[l,r],xorsum=这个区间所有异或和,min = 区间最小值,max = 区间最大值,要求xorsum ^ min ^ max最大。

解题思路

对于xor最大,我们一般会往两个方向想:一.线性基 二.01字典树
这题是用字典树。如果只是求xorsum最大,我们可以维护一个前缀异或和的字典树,然后每次得到新的前缀异或和,先在字典树查一下能得到的最大值,再插入字典树。但是这里还有最大值和最小值,由于是统计区间信息,所以我们来考虑分治:
对于当前区间[l,r],统计出所有左端点在[l,mid],右端点在[mid+1,r]的区间的信息,然后再递归[l,mid]和[mid+1,r]。那么我们现在需要做的就是快速统计跨越mid的区间信息。这个时候可以分成四种情况:

  1. 最大值和最小值都在左边
  2. 最大值和最小值都在右边
  3. 最大值在左边,最小值在右边
  4. 最小值在左边,最大值在右边

对于第一种情况,我们在字典树上插入右半边可取的前缀异或和,然后对于每一个左端点查询 它的后缀异或和 ^ min ^ max可以在字典树上合出的最大值。
我们可以从大到小枚举左端点,可以发现左端点越小,右端点的可取范围就越大。所以每次改变左端点之后,就可以在字典树上插入信息。
第二张情况和第一种情况类似
对于第三种情况,最大值要在左边,最小值要在右边,所以右端点可以取的最小值和最大值都有限制,每次移动左端点的时候,要改变右端点范围,并根据范围在字典树上插入和删除值。
第四种情况和第三种类似。
这里有一个trick:可以只统计第一种情况和第三种情况,然后把数组倒过来再统计一遍,可以减少码量。

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
const int maxn = 1e5 + 50;
const int inf = 0x3f3f3f3f;
int ch[maxn*40][2], cnt[maxn*40], tot;
int a[maxn], n, ans;
void clr(){
   
    tot = 0; ch[tot][0] = ch[tot][1] = 0; cnt[tot] = 0;
}
void ins(int x){
   
   // cout<<"add:"<<x<<endl;
    int rt = 0;
    for(int i = 30; i >= 0
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值