#include #include #include #include #include using namespace std; // 定义常量 const int INF = 1e9 + 7; const int MAXN = 20005; // 全局变量 int N, Q; int A[MAXN]; // 原数组 // 排序后的结构: (数值, 原始下标) vector> sorted_A; // 每个原始下标位置可能对应多个相邻对的异或值(因为可能会有多个对的max_index相同) // 使用 multiset 维护每个下标位置当前的所有候选异或值 multiset idx_contributions[MAXN]; // 线段树:维护区间最小值 int tree[4 * MAXN]; // 更新线段树单点 void update_tree(int node, int start, int end, int idx, int val) { if (start == end) { tree[node] = val; return; } int mid = (start + end) / 2; if (idx <= mid) update_tree(2 * node, start, mid, idx, val); else update_tree(2 * node + 1, mid + 1, end, idx, val); tree[node] = min(tree[2 * node], tree[2 * node + 1]); } // 查询线段树区间最小值 int query_tree(int node, int start, int end, int l, int r) { if (r < start || end < l) return INF; if (l <= start && end <= r) return tree[node]; int mid = (start + end) / 2; return min(query_tree(2 * node, start, mid, l, r), query_tree(2 * node + 1, mid + 1, end, l, r)); } // 辅助函数:向系统添加一对相邻元素的贡献 void add_contribution(const pair& p1, const pair& p2) { int xor_val = p1.first ^ p2.first; int max_idx = max(p1.second, p2.second); idx_contributions[max_idx].insert(xor_val); // 更新线段树为该位置当前的最小值 update_tree(1, 1, N, max_idx, *idx_contributions[max_idx].begin()); } // 辅助函数:从系统移除一对相邻元素的贡献 void remove_contribution(const pair& p1, const pair& p2) { int xor_val = p1.first ^ p2.first; int max_idx = max(p1.second, p2.second); auto it = idx_contributions[max_idx].find(xor_val); if (it != idx_contributions[max_idx].end()) { idx_contributions[max_idx].erase(it); } // 更新线段树 if (idx_contributions[max_idx].empty()) { update_tree(1, 1, N, max_idx, INF); } else { update_tree(1, 1, N, max_idx, *idx_contributions[max_idx].begin()); } } int main() { // 优化 I/O ios_base::sync_with_stdio(false); cin.tie(NULL); if (!(cin >> N >> Q)) return 0; for (int i = 1; i <= N; ++i) { cin >> A[i]; sorted_A.push_back({A[i], i}); } // 初始排序 sort(sorted_A.begin(), sorted_A.end()); // 初始化线段树值为 INF fill(tree, tree + 4 * MAXN, INF); // 构建初始贡献 for (int i = 0; i < N - 1; ++i) { add_contribution(sorted_A[i], sorted_A[i+1]); } for (int q = 0; q < Q; ++q) { int type; cin >> type; if (type == 1) { int i, x; cin >> i >> x; // 1. 在 sorted_A 中找到旧值 A[i] // 使用 lower_bound 二分查找,但因为值可能重复,需要检查 index pair target = {A[i], i}; auto it = lower_bound(sorted_A.begin(), sorted_A.end(), target); // lower_bound 可能找到数值相同但 index 不同的元素,必须精确匹配 // 由于我们总是存 (val, index),且 index 唯一,所以可以直接比较 // 但为了保险(如果有多重集逻辑),可以用 while 循环微调,但在 vector 默认排序下是精确的。 int idx_in_sorted = distance(sorted_A.begin(), it); // 2. 删除旧贡献 (与前一个,与后一个) if (idx_in_sorted > 0) { remove_contribution(sorted_A[idx_in_sorted - 1], sorted_A[idx_in_sorted]); } if (idx_in_sorted < sorted_A.size() - 1) { remove_contribution(sorted_A[idx_in_sorted], sorted_A[idx_in_sorted + 1]); } // 此时如果前后都有,删除后,原来的 前-后 变成了相邻,需要添加吗? // 答:不需要在这里添加,因为我们马上要插入新元素,打断这个连接。 // 不,稍等。逻辑是:删除一个元素后,原来的 前 和 后 变成了相邻。 // 但我们是“修改”,即“删除旧的,插入新的”。 // 为了逻辑清晰,我们可以先视为“删除”,加上(前, 后)的贡献,然后再“插入”,打断。 // 实际上直接操作 vector 比较直观: // 若删除位置 idx,则 idx-1 和 idx+1 变为相邻 if (idx_in_sorted > 0 && idx_in_sorted < sorted_A.size() - 1) { add_contribution(sorted_A[idx_in_sorted - 1], sorted_A[idx_in_sorted + 1]); } // 从 vector 中移除 sorted_A.erase(it); // 3. 插入新值 A[i] = x; target = {x, i}; // 找到新位置 it = upper_bound(sorted_A.begin(), sorted_A.end(), target); idx_in_sorted = distance(sorted_A.begin(), it); // 插入 vector sorted_A.insert(it, target); // 处理新位置的贡献 // 插入位置现在是 idx_in_sorted // 新的邻居是 idx_in_sorted-1 和 idx_in_sorted+1 // 如果插入到了中间,原来的 (idx-1, idx+1) 不再相邻,需要移除贡献 if (idx_in_sorted > 0 && idx_in_sorted < sorted_A.size() - 1) { remove_contribution(sorted_A[idx_in_sorted - 1], sorted_A[idx_in_sorted + 1]); } // 添加新贡献 if (idx_in_sorted > 0) { add_contribution(sorted_A[idx_in_sorted - 1], sorted_A[idx_in_sorted]); } if (idx_in_sorted < sorted_A.size() - 1) { add_contribution(sorted_A[idx_in_sorted], sorted_A[idx_in_sorted + 1]); } } else { int r; cin >> r; // 查询前 r 个元素的最小异或 // 即查询线段树区间 [1, r] 的最小值 // 注意:我们的贡献是记在 max(i, j) 上的,所以只有当 i, j <= r 时,贡献才会被查询到。 // 且我们的 multiset/SegTree 索引是 1 到 N。 int ans = query_tree(1, 1, N, 1, r); cout << ans << "\n"; } } return 0; }