P4735 最大异或和(可持久化trie树模板)

间隙

题目描述

给定一个非负整数序列 \(\{a\}\),初始长度为\(n\)

\(m\) 个操作,有以下两种操作类型:

A x:添加操作,表示在序列末尾添加一个数 \(x\),序列的长度 \(n+1\)

Q l r x:询问操作,你需要找到一个位置 \(p\),满足\(x⊕a[p]⊕a[p+1]⊕...⊕a[N]⊕x\)最大,输出最大是多少。

\(N,M≤300000\)

分析

可持久化trie树模板

\(s[i]\)表示前\(i\)个数\(⊕\)起来的结果,根据异或的性质:

\(a_p⊕a_{p+1}⊕...⊕a[n]⊕x = s[p-1]⊕s[n]⊕x\)

对于添加操作,直接插入即可

对于查询操作:

维护一个数组\(b_i\),表示节点\(b_i\)的子树中的最大版本号(最大下标)

显然,只有在最大版本号不小于\(l-1\)时该节点才合法,在合法的前提下尽可能地往与当前位相反的指针走

\(code\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 600010;
int n,m,child[MAXN*24][2], tot;
int s[MAXN],a[MAXN],root[MAXN],maxindex[MAXN*24];
void update(int node){
	maxindex[node] = max(maxindex[child[node][0]],maxindex[child[node][1]]);
}
void insert(int node,int now,int ind,int last){
	if(now<0){
		maxindex[node] = ind;
		return;
	}
	int c = s[ind]>>now&1;
	if(last) child[node][c^1] = child[last][c^1];
	child[node][c] = ++tot;
	insert(child[node][c],now-1,ind,child[last][c]);
	update(node);
}
int query(int node,int now,int val,int limit){
	if(now<0){
		return s[maxindex[node]]^val;
	}
	int c = val>>now&1;
	if(maxindex[child[node][c^1]]>=limit){
		return query(child[node][c^1],now-1,val,limit);
	}
	else{
		return query(child[node][c],now-1,val,limit);
	}
}

int main(){
	cin>>n>>m;
	maxindex[0] = -1;//坑
	root[0] = ++tot;
	insert(root[0],23,0,0);
	for(int i=1;i<=n;i++){
		int x;
		scanf("%d",&x);
		s[i] = s[i-1]^x;
		root[i] = ++tot;
		insert(root[i],23,i,root[i-1]);
	}
	for(int i=1;i<=m;i++){
		char opt[2];
		scanf("%s",opt);
		if(opt[0]=='A'){
			int val;
			scanf("%d",&val);
			root[++n] = ++tot;
			s[n] = s[n-1]^val;
			insert(root[n],23,n,root[n-1]);
		}
		else{
			int l,r,x;
			scanf("%d%d%d",&l,&r,&x);
			printf("%d\n",query(root[r-1],23,x^s[n],l-1));
		}
	}
	
}
posted @ 2020-10-31 21:36  xcxc82  阅读(92)  评论(0编辑  收藏  举报