文章历史

2022-08-03: 文章初稿,由于对算法介绍过于少而被管理员打回重造。

2020-08-06:将算法介绍进行扩写,并删除了一些可有可无的内容或玩梗内容。

管理员审核题解辛苦了。

简要题意

(这道题描述是真的长)

你需要维护一个数据结构,支持单点异或和区间求最大异或和。

思路

思维过程

对于这种区间问题,最容易想到的就是线段树。

而对于复杂的异或问题,最容易想到的就是线性基。

合在一起,就是线段树套线性基,类似经典的树套树。

详细思路

线段树大家应该都会,如果不会建议学习一下,这是一个很有用的数据结构。

线性基大家应该都会,如果不会可以看 这篇博客

首先,每一个线段树节点,都保存一个线性基。(单个线性基空间复杂度为 \(O(\log\max\{x\})\),是可以接受的,不用担心会MLE)

首先,对于修改操作,我们不方便 \(\operatorname{pushup}\),那么我们可以想到一个更好的方法:就是我们线段树DFS到的每一个区间节点都包含着修改值,那么我们考虑像权值线段树那样,经过一个点都把修改的元素插入节点线性基。

查询,我们可以考虑实现一个操作 \(\operatorname{expand}\),表示用一个新的线性基扩展原来的线性基(说人话:将另一个线性基的所有元素都插入原来的线性基)

\(\operatorname{expand}\) 操作有一个简单有效的优化常数的方法,就是遍历线性基数组时,仅插入非 \(0\) 值。

然后,我们就可以像经典的线段树那样实现,只不过将维护信息并的运算符换成 \(\operatorname{expand}\) 即可。

(注:有的同学可能习惯将我的 \(\operatorname{expand}\) 操作换成类似线性基加法的 \(\operatorname{merge}\),这一点看大家个人喜好)

时间复杂度 \(O(n\log m\log^{2}\max\{x\})\),空间复杂度 \(O(n\log\max\{x\})\),可以通过本题。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std; namespace Basis{
const int MAX_BIT = 60;
struct Basis{
int p[MAX_BIT+5];
int _how_many_numbers_can_xor;
void clear(){
memset(p,0,sizeof(p));
_how_many_numbers_can_xor=0;
}
Basis(){
clear();
}
void insert(int x){
for(int i=MAX_BIT;i>=0;i--){
if(!(x>>i))continue;
if(!p[i]){
p[i]=x;
_how_many_numbers_can_xor++;
break;
}
x^=p[i];
}
}
int max_xor(){
int ans=0;
for(int i=MAX_BIT;i>=0;i--){
if((ans^p[i])>ans){
ans^=p[i];
}
}
return ans;
}
bool can_be_xor(int x){
for(int i=MAX_BIT;i>=0;i--){
if(x&(1ll<<i))x^=p[i];
}
return x==0;
}
int numbers_can_xor(){
return (1ll<<_how_many_numbers_can_xor);
}
void expand(Basis &x){
for(int i=MAX_BIT;i>=0;i--){
if(x.p[i]){
insert(x.p[i]);
}
}
}
};
} namespace sgt{
Basis::Basis t[200005];
void update(int x,int v,int i,int l,int r){
t[i].insert(v);
if(l==r){
return;
}
int mid=(l+r)>>1;
if(x<=mid){
update(x,v,i<<1,l,mid);
}
else{
update(x,v,i<<1|1,mid+1,r);
}
}
Basis::Basis result;
void query(int ql,int qr,int i,int l,int r){
if(ql<=l&&qr>=r){
result.expand(t[i]);
return;
}
int mid=(l+r)>>1;
if(ql<=mid){
query(ql,qr,i<<1,l,mid);
}
if(qr>mid){
query(ql,qr,i<<1|1,mid+1,r);
}
}
} int n,m; signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
while(n--){
int op,a,b;
cin>>op>>a>>b;
if(op==1){
sgt::update(a,b,1,1,m);
}
else{
sgt::result.clear();
sgt::query(a,b,1,1,m);
cout<<sgt::result.max_xor()<<'\n';
}
}
return 0;
}

加强版:P5607 [Ynoi2013] 无力回天 NOI2017

如果将单点修改变成区间修改,那么应该如何处理呢?可以思考一下。(提示:想想差分)

P5607 [Ynoi2013] 无力回天 NOI2017 题解

最新文章

  1. liaoliao的四连做第二弹
  2. PL/SQL Developer记住用户名密码
  3. HDU 4003 [树][贪心][背包]
  4. 深度技术32位Win7系统Ghost版
  5. EDIUS手绘遮罩功能如何用
  6. javascript 搜索二叉树
  7. BLE-NRF51822教程16-BLE地址
  8. phpcms 04
  9. DWR在Spring中应用
  10. bzoj1079
  11. luajit 安装cjson
  12. Lang语言包
  13. docker Swarm 集群发现
  14. Lintcode212 Space Replacement solution 题解
  15. JavaScript深入之从原型到原型链
  16. Codeforces 442C Artem and Array (看题解)
  17. 穿透内网,连接动态ip,内网ip打洞-----p2p实现原理(转)
  18. Cocos2d-x 3.2 打包Android平台APK
  19. POJ 2263 最短路Floyd_warshall算法
  20. PHP权限控制(转)

热门文章

  1. 有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来。
  2. JavaScript中的代码执行顺序
  3. Unexpected token u in JSON at position 0
  4. MasaFramework -- 缓存入门与设计
  5. Docker基础和常用命令
  6. Java自定义排序:继承Comparable接口,重写compareTo方法(排序规则)
  7. Arch Linux 的安装
  8. hwlog--logger.go
  9. Go实现常用软件设计模式二:工厂模式
  10. hashcat 命令