[可持久化01Trie] BZOJ 3261 最大异或和

给定一个非负整数序列{a},初始长度为N。

有M个操作,有以下两种操作类型:

1、Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。

2、Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得:

a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少。

Input

第一行包含两个整数 N  ,M,含义如问题描述所示。   
第二行包含 N个非负整数,表示初始的序列 A 。 
接下来 M行,每行描述一个操作,格式如题面所述。   

Output

假设询问操作有 T个,则输出应该有 T行,每行一个整数表示询问的答案。

Sample Input

5 5

2 6 4 3 6

A 1

Q 3 5 4

A 4

Q 5 7 0

Q 3 6 6

对于测试点 1-2,N,M<=5 。 对于测试点 3-7,N,M<=80000 。 对于测试点 8-10,N,M<=300000 。 其中测试点 1, 3, 5, 7, 9保证没有修改操作。 0<=a[i]<=10^7。

Sample Output

4 5 6

 题意如上, 求值为 max(a[pos] \, _{xor}\, a[n] \, _{xor} \, val) \, (x <= p <= y)

异或有前缀性质,对数组进行前缀异或处理 (下标1为0, xiabiao 2为a[1]) 

则 a[pos] \, _{xor}\, a[n] \, _{xor} \, val  可直接将 val 与 a[n] 异或后在x, y 区间内找一个最大前缀异或值即为答案

对于区间内最大异或值用可持久化01trie记录当前根内前缀节点和的数量

当 sum[ tr[nto][dig] ] - sum[ tr[lto][dig] ] 时说明此区间内该节点有至少一个

然后按正常的异或贪心gao一下即可

代码:


/*
    Zeolim - An AC a day keeps the bug away
*/
 
//#pragma GCC optimize(2)
//#pragma GCC ("-W1,--stack=128000000")
#include <bits/stdc++.h>
using namespace std;
#define mp(x, y) make_pair(x, y)
#define fr(x, y, z) for(int x = y; x < z; ++x)
#define pb(x) push_back(x)
#define mem(x) memset(x, 0, sizof(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef std::pair <int, int> pii;
typedef std::vector <int> vi;
//typedef __int128 ill;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 386910137;
const ull P = 13331; 
const int MAXN = 6e5 + 10;

struct trie
{
	int cnt, root[MAXN], tr[MAXN * 25][2], sum[MAXN * 25];
	
	trie() {cnt = 0;}
	
	void insert(int now, int last, int val) 
	{
		int nto, lto;
		root[now] = nto = ++cnt;
		lto = root[last];
		for(int i = 23; i >= 0; --i)
		{
			int dig = val >> i & 1;
			tr[nto][0] = tr[lto][0];
			tr[nto][1] = tr[lto][1];
			tr[nto][dig] = ++cnt, nto = cnt;
			lto = tr[lto][dig];
			sum[nto] = sum[lto] + 1;
		}
	}
	
	int get(int now, int last, int val)
	{
		int ret = 0;
		int nto = root[now], lto = root[last];
		for(int i = 23; i >= 0; --i)
		{
			int dig = val >> i & 1 ^ 1;
			if(sum[ tr[nto][dig] ] - sum[ tr[lto][dig] ])
				ret += (1 << i), nto = tr[nto][dig], lto = tr[lto][dig];
			else
				nto = tr[nto][dig ^ 1], lto = tr[lto][dig ^ 1];
		}
		return ret;
	}
}T;

int arr[MAXN];

int main()
{  
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    //freopen("d:out.txt","w",stdout);
    //freopen("d:in.txt","r",stdin);
    
	int n, m;
	
	cin >> n >> m;
	
	++n;
	
	T.insert(1, 0, 0);
	
	for(int i = 2, t; i <= n; ++i)
	{
		cin >> arr[i];
		arr[i] ^= arr[i - 1];
		T.insert(i, i - 1, arr[i]);
	}
	
	while(m--)
	{
		char op;
		
		int x, y, val;
		
		cin >> op;
		
		if(op == 'A')
		{
			cin >> x;
			arr[++n] = x;
			arr[n] ^= arr[n - 1];
			T.insert(n, n - 1, arr[n]);
		}
		else
		{
			cin >> x >> y >> val;

			cout << T.get(y, x - 1, arr[n] ^ val) << '
';
		}
	}

    return 0;
}
原文地址:https://www.cnblogs.com/zeolim/p/12270346.html