线段树套线性基——题解P4839 P哥的桶
文章历史
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 题解
线段树套线性基——题解P4839 P哥的桶的更多相关文章
- BZOJ.4184.shallot(线段树分治 线性基)
BZOJ 裸的线段树分治+线性基,就是跑的巨慢_(:з」∠)_ . 不知道他们都写的什么=-= //41652kb 11920ms #include <map> #include < ...
- bzoj 4184: shallot (线段树维护线性基)
题面 \(solution:\) 这一题绝对算的上是一道经典的例题,它向我们诠释了一种新的线段树维护方式(神犇可以跳过了).像这一类需要加入又需要维护删除的问题,我们曾经是遇到过的像莫对,线段树... ...
- $CF938G\ Shortest\ Path\ Queries$ 线段树分治+线性基
正解:线段树分治+线性基 解题报告: 传送门$QwQ$ 考虑如果只有操作3,就这题嘛$QwQ$ 欧克然后现在考虑加上了操作一操作二 于是就线段树分治鸭 首先线段树叶子节点是询问嘛这个不用说$QwQ$. ...
- 【BZOJ4184】shallot 线段树+vector+线性基
[BZOJ4184]shallot Description 小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏. 每个时刻她会给小葱一颗小葱苗或者是从 ...
- 2017 ICPC西安区域赛 A - XOR (线段树并线性基)
链接:https://nanti.jisuanke.com/t/A1607 题面: Consider an array AA with n elements . Each of its eleme ...
- 【luogu3733】【HAOI2017】 八纵八横 (线段树分治+线性基)
Descroption 原题链接 给你一个\(n\)个点的图,有重边有自环保证连通,最开始有\(m\)条固定的边,要求你支持加边删边改边(均不涉及最初的\(m\)条边),每一次操作都求出图中经过\(1 ...
- LOJ 2312(洛谷 3733) 「HAOI2017」八纵八横——线段树分治+线性基+bitset
题目:https://loj.ac/problem/2312 https://www.luogu.org/problemnew/show/P3733 原本以为要线段树分治+LCT,查了查发现环上的值直 ...
- BZOJ4184:shallot(线段树分治,线性基)
Description 小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏. 每个时刻她会给小葱一颗小葱苗或者是从小葱手里拿走一颗小葱苗,并且 让小葱 ...
- 2017西安区域赛A / UVALive - 8512 线段树维护线性基合并
题意:给定\(a[1...n]\),\(Q\)次询问求\(A[L...R]\)的异或组合再或上\(K\)的最大值 本题是2017的西安区域赛A题,了解线性基之后你会发现这根本就是套路题.. 只要用线段 ...
- 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横
不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...
随机推荐
- Nginx通用优化示例
user nginx; worker_processes auto; #worket_cpu_affinity auto; error_log /var/log/nginx/error.log war ...
- Ruoyi表单构建
Ruoyi表单构建通过拖动组件就能自动生成前端代码,很方便,所以本文简单通过上层函数源码来梳理一下大致流程,如有需要再自行仔细一行行分析底层代码. 组件拖动 实现组件拖动功能主要依赖第三方库:VueD ...
- Vue router简单配置入门案例
{ 注意驼峰命名法,不然会报错 } 1.在Views文件夹下创建Vue路由文件,例如: <template> </template> <script> </ ...
- ubuntu 安装anaconda3
ubuntu 安装anaconda3 官网:https://www.anaconda.com/ 下载:https://www.anaconda.com/products/individual#Down ...
- 谷歌浏览器xpath获取网页按钮路径
谷歌浏览器打开要获取的页面按下F12打开开发者工具 点击最左边的元素选择器,高亮后光标移动到对应元素框(这里只选择里层的元素,如这里要选到input级别) 点击后下方HTML会高亮显示,鼠标移动上去右 ...
- 将Oracle数据库迁移到达梦数据库
公司某产品在项目现场上常用到的数据库有Oracle和达梦. 做性能测试需要根据项目现场预埋大量的基础数据和业务数据,耗费时间.精力.故完成Oracle数据库的性能测试之后,采用直接将Oracle数据库 ...
- git pull与git pull --rebase
aliases: [] tags: [git] link: date: 2022-08-30 目录 git pull --rebase 等效命令 总结 参考文章 git pull --rebase 在 ...
- 【翻译】Thymeleaf – Spring Security集成模块
原文链接:Thymeleaf - Spring Security integration modules 来源:thymeleaf/thymeleaf-extras-springsecurity自述文 ...
- perl大小写转换函数uc和lc
$side = uc $attrs[0]; #把attrs[0]转换成大写,然后给side变量赋值. $gender = lc $attrs[1]; #把attrs[1]转换成小写,然后给gender ...
- scrapy框架命令
scrapy startproject #创建scrapy项目 scrapy genspider test www.baidu.com #在项目下的spider目录下生成爬虫文件 test爬虫名称 w ...