P4839 P哥的桶
作者:互联网
简要题意
(这道题描述是真的长)
你需要维护一个数据结构,支持单点异或和区间求最大异或和。
思路
对于这种区间问题,最容易想到的就是 分块 线段树。
而对于复杂的异或问题,最容易想到的就是 01 Trie 线性基。
合在一起,就是线段是套线性基。(好像还用了顶针的手法)
线段树套线性基不难写,我们可以每一个线段树节点维护一个线性基,然后修改就是插入,查询就把所有查询到的节点合并到一个线性基中,然后再线性基中查询。
线性基想必大家都会,如果不会可以看 这篇博客。
代码
#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 题解
标签:xor,Basis,int,MAX,P4839,ans,-- 来源: https://www.cnblogs.com/zheyuanxie/p/solution-p4839.html