题目描述

E. Choosing The Commander
[2000]

time limit per test2 seconds
memory limit per test256 megabytes
As you might remember from the previous round, Vova is currently playing a strategic game known as Rage of Empires.

Vova managed to build a large army, but forgot about the main person in the army - the commander. So he tries to hire a commander, and he wants to choose the person who will be respected by warriors.

Each warrior is represented by his personality — an integer number pi. Each commander has two characteristics — his personality pj and leadership lj (both are integer numbers). Warrior i respects commander j only if ( is the bitwise excluding OR of x and y).

Initially Vova’s army is empty. There are three different types of events that can happen with the army:

1 pi — one warrior with personality pi joins Vova’s army;
2 pi — one warrior with personality pi leaves Vova’s army;
3 pi li — Vova tries to hire a commander with personality pi and leadership li.
For each event of the third type Vova wants to know how many warriors (counting only those who joined the army and haven’t left yet) respect the commander he tries to hire.

Input
The first line contains one integer q (1 ≤ q ≤ 100000) — the number of events.

Then q lines follow. Each line describes the event:

1 pi (1 ≤ pi ≤ 108) — one warrior with personality pi joins Vova’s army;
2 pi (1 ≤ pi ≤ 108) — one warrior with personality pi leaves Vova’s army (it is guaranteed that there is at least one such warrior in Vova’s army by this moment);
3 pi li (1 ≤ pi, li ≤ 108) — Vova tries to hire a commander with personality pi and leadership li. There is at least one event of this type.
Output
For each event of the third type print one integer — the number of warriors who respect the commander Vova tries to hire in the event.

Example

1
2
3
4
5
6
7
8
9
10
Input
5
1 3
1 4
3 6 3
2 4
3 6 3
Output
1
0

思路

This problem is a classic application of a 01-Trie (also known as a Binary Trie or Radix Tree).The core of the problem is to efficiently count how many warrior personalities $p_i$ in the current army satisfy the condition $p_i \oplus p_j < l_j$ for a given commander ($p_j, l_j$). The combination of a bitwise operation ($\oplus$, XOR) and a comparison ($<$) is a strong hint for using a Trie.

  1. Handling Events 1 & 2 (Add / Remove Warrior)

We’ll create a single insert(p, val) function.

  • To add a warrior p (Event 1), we call insert(p, 1).

  • To remove a warrior p (Event 2), we call insert(p, -1).

How insert works:

1. Start at the root node.

2. Iterate through the bits of p from the MSB (e.g., bit 29) down to bit 0.

3. At each bit k, find the value bit = (p >> k) & 1.

4. If the child node curr->ch[bit] doesn't exist, create it.

5. Move to that child node: curr = curr->ch[bit].

6.Crucially: Update the child's counter: curr->sz += val.

This way, sz at any node always reflects the exact number of active warriors whose binary representation follows that path.

  1. Handling Event 3 (Query)This is the most complex part. We need to find the count of $p_i$ (which we’ll call $x$) such that $x \oplus p < l$.

We create a recursive function query(curr, p, l, k) which means:

“Starting at node curr (which corresponds to bit k+1’s prefix), how many warriors $x$ in this subtree satisfy the condition, given we are now comparing bit k?”

We traverse the trie and the bits of $p$ and $l$ simultaneously from MSB (bit k = MAX_BIT) down to 0.

At each bit k, we look at p_bit = (p >> k) & 1 and l_bit = (l >> k) & 1. We want to find paths $x$ (with bit x_bit) such that $(x_bit \oplus p_bit) < l_bit$.

The Recursive Logic:

Let ans = 0.Case 1: l_bit == 1

$l$’s current bit is 1. We are checking for $(x \oplus p)$’s bit to be $< 1$. This means it can be 0 or 1.

Path A: Try to make $(x \oplus p)$’s bit = 0.

  • This requires $x_bit = p_bit$.

  • If we follow this path (to curr->ch[p_bit]), we have $(x \oplus p)_k = 0$, which is strictly less than $l_k = 1$.

  • Success! The condition $x \oplus p < l$ is already met, regardless of the lower bits.

  • Therefore, all warriors in this entire subtree (curr->ch[p_bit]) are valid.

  • We add its total count: ans += curr->ch[p_bit]->sz (if that node exists).

Path B: Try to make $(x \oplus p)$’s bit = 1.

  • This requires $x_bit = 1 - p_bit$.

  • If we follow this path (to curr->ch[1 - p_bit]), we have $(x \oplus p)_k = 1$, which is equal to $l_k = 1$.

  • The result is a tie. The winner is decided by the remaining lower bits.

  • We must continue checking recursively: ans += query(curr->ch[1 - p_bit], p, l, k - 1).

Case 2: l_bit == 0

$l$’s current bit is 0. We are checking for $(x \oplus p)$’s bit to be $< 0$.

This is impossible. The only way to not fail the condition is for $(x \oplus p)$’s bit to be equal to 0.

Path A: Try to make $(x \oplus p)$’s bit = 0.

  • This requires $x_bit = p_bit$.
  • If we follow this path (to curr->ch[p_bit]), we have $(x \oplus p)_k = 0$, which is equal to $l_k = 0$.
  • The result is a tie. We must continue checking recursively: ans += query(curr->ch[p_bit], p, l, k - 1).

Path B: Try to make $(x \oplus p)$’s bit = 1.

  • This requires $x_bit = 1 - p_bit$.
  • This would make $(x \oplus p)_k = 1$, which is greater than $l_k = 0$.
  • Failure! This path (and all warriors in its subtree) fails the $x \oplus p < l$ condition.
  • We do nothing (add 0).

Base Cases:

  • If curr == NULL (the path doesn’t exist), return 0.
  • If k == -1 (we’ve compared all bits), it means $x \oplus p$ was equal to $l$ all the way down. Since we need strictly less than, this path does not count. Return 0.

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <iostream>

using namespace std;

// 10^8 is less than 2^30, so we need bits 0 through 29.
const int MAX_BIT = 29;

// The 01-Trie Node
struct Node {
Node* ch[2]; // ch[0] for bit 0, ch[1] for bit 1
int sz; // Count of active warriors with this prefix

Node() {
ch[0] = ch[1] = NULL;
sz = 0;
}
};

Node* root; // Global root of the Trie

/**
* @brief Inserts (val=1) or removes (val=-1) a number p.
*/
void insert(int p, int val) {
Node* curr = root;
for (int k = MAX_BIT; k >= 0; k--) {
int bit = (p >> k) & 1; // Get the k-th bit of p

if (curr->ch[bit] == NULL) {
curr->ch[bit] = new Node();
}

curr = curr->ch[bit];
curr->sz += val; // Update the count for this prefix
}
}

/**
* @brief Counts warriors x such that x ^ p < l.
* @param curr Current Trie node
* @param p Commander's personality
* @param l Commander's leadership
* @param k Current bit we are comparing
* @return The count of respecting warriors in this subtree
*/
int query(Node* curr, int p, int l, int k) {
// Base Case 1: This path doesn't exist for any warrior.
if (curr == NULL) {
return 0;
}
// Base Case 2: We've compared all bits. x^p == l, not < l.
if (k == -1) {
return 0;
}

int p_bit = (p >> k) & 1; // p's k-th bit
int l_bit = (l >> k) & 1; // l's k-th bit
int ans = 0;

if (l_bit == 1) {
// l's bit is 1.

// Path A: Try to make (x^p) bit = 0.
// This means x_bit = p_bit.
// (x^p)_k = 0 < l_k = 1. This path wins.
// Add all warriors in this subtree.
if (curr->ch[p_bit] != NULL) {
ans += curr->ch[p_bit]->sz;
}

// Path B: Try to make (x^p) bit = 1.
// This means x_bit = 1 - p_bit.
// (x^p)_k = 1 == l_k = 1. This path is a tie.
// Must check lower bits.
if (curr->ch[1 - p_bit] != NULL) {
ans += query(curr->ch[1 - p_bit], p, l, k - 1);
}

} else { // l_bit == 0
// l's bit is 0.

// We MUST make (x^p) bit = 0.
// Path A: Try to make (x^p) bit = 0.
// This means x_bit = p_bit.
// (x^p)_k = 0 == l_k = 0. This path is a tie.
// Must check lower bits.
if (curr->ch[p_bit] != NULL) {
ans += query(curr->ch[p_bit], p, l, k - 1);
}

// Path B: (x^p) bit = 1.
// This means x_bit = 1 - p_bit.
// (x^p)_k = 1 > l_k = 0. This path fails.
// Do nothing.
}

return ans;
}

int main() {
// Faster I/O
ios_base::sync_with_stdio(false);
cin.tie(NULL);

root = new Node(); // Initialize the Trie

int q;
cin >> q;

while (q--) {
int type;
cin >> type;
if (type == 1) {
int p;
cin >> p;
insert(p, 1); // Add warrior
} else if (type == 2) {
int p;
cin >> p;
insert(p, -1); // Remove warrior
} else {
int p, l;
cin >> p >> l;
// Start query from the root and the highest bit
cout << query(root, p, l, MAX_BIT) << "\n";
}
}

return 0;
}