[BZOJ 4103] [Thu Summer Camp 2015] 異或運算 【可持久化Trie】

題目連接:BZOJ - 4103php

 

題目分析

THUSC滾粗以後一直沒有寫這道題,歷來沒寫過可持久化Trie,發現其實和可持久化線段樹都是同樣的。嗯,有些東西就是明白得太晚。ios

首先Orz ZYF-ZYF 神犇的題解。數組

題目給出的 n 和 m 的範圍差異很大,n 很小,m 很大,所以能夠想到 n 的範圍是爲了直接暴力枚舉。ui

題目要求的就是 A 的一段區間中的數和 B 的一段區間中的數的異或的第 k 大值。spa

位運算有關的題目,通常是從高位到低位貪心之類的。blog

區間異或,通常要使用可持久化 Trie。get

咱們對於範圍大的 B 數組創建可持久化 Trie,這樣就能夠提取 B 數組的一個區間了。博客

從高位到低位,枚舉 A 數組區間中的每一個元素,根據 Trie 結點的信息,求出這一位爲 0 和 爲 1 的各有多少,並據此肯定答案的這一位。string

要注意的是,A 數組區間中每一個元素要對應的 Trie 結點是不一樣的,由它們的前幾位肯定(由於它們的前幾位不一樣,可是要求異或以後前幾位相同)。it

編輯完這篇博客以後仍是一個一個地添加了標籤,雖然這個blog立刻就要停更了,感受這幾天寫的任何一篇都有多是最後一篇。

奇怪的感受。

 

代碼

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int MaxN = 1000 + 5, MaxM = 300000 + 5, MaxNode = 10000000 + 5;

int n, m, p, Index, Ans;
int A[MaxN], B[MaxM], Root[MaxM], Son[MaxNode][2], T[MaxNode], F[MaxN], Q[MaxN];

bool OK[MaxN];

void Build(int &x, int y, int Num, int Bit)
{
	if (!x) x = ++Index;
	if (Bit == 0)
	{
		T[x] = T[y] + 1;
		return;
	}
	if (Num & (1 << (Bit - 1)))
	{
		Son[x][0] = Son[y][0];
		Build(Son[x][1], Son[y][1], Num, Bit - 1);
	}
	else
	{
		Son[x][1] = Son[y][1];
		Build(Son[x][0], Son[y][0], Num, Bit - 1);
	}
	T[x] = T[Son[x][0]] + T[Son[x][1]];
}

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) scanf("%d", &A[i]);
	for (int i = 1; i <= m; ++i) 
	{
		scanf("%d", &B[i]);
		Build(Root[i], Root[i - 1], B[i], 31);
	}
	scanf("%d", &p);
	int u, d, l, r, kk;
	for (int i = 1; i <= p; ++i)
	{
		scanf("%d%d%d%d%d", &u, &d, &l, &r, &kk);
		kk = (d - u + 1) * (r - l + 1) - kk + 1; 
		Ans = 0;
		for (int j = u; j <= d; ++j)
		{
			F[j] = Root[r];
			Q[j] = Root[l - 1];
		}
		for (int j = 30; j >= 0; --j)
		{
			int x, Temp = 0;
			for (int k = u; k <= d; ++k)
			{
				x = (A[k] & (1 << j));
				if (x) Temp += T[Son[F[k]][1]] - T[Son[Q[k]][1]];
				else Temp += T[Son[F[k]][0]] - T[Son[Q[k]][0]];
			}
			if (Temp >= kk)
			{
				for (int k = u; k <= d; ++k)
				{
					x = (A[k] & (1 << j));
					if (x) 
					{
						F[k] = Son[F[k]][1];
						Q[k] = Son[Q[k]][1];
					}
					else
					{
						F[k] = Son[F[k]][0];
						Q[k] = Son[Q[k]][0];
					}
				}
			}
			else
			{
				kk -= Temp;
				Ans |= (1 << j);				
				for (int k = u; k <= d; ++k)
				{
					x = (A[k] & (1 << j));
					if (x) 
					{
						F[k] = Son[F[k]][0];
						Q[k] = Son[Q[k]][0];
					}
					else
					{
						F[k] = Son[F[k]][1];
						Q[k] = Son[Q[k]][1];
					}
				}
			}
		}
		printf("%d\n", Ans);
	}
	return 0;
}
相關文章
相關標籤/搜索