【题目链接】
【思路要点】
- 前缀和后用可持久化线段树可以计算出各个右端点对应的最优的左端点,并且可以实现在某一个左端点集合中单点删除。
- 用堆维护全局最优值,每找到一个便将其在对应的线段树中删除即可。
- 时间复杂度 O ( N L o g V + K L o g V ) O(NLogV+KLogV) O(NLogV+KLogV) 。
【代码】
#include<bits/stdc++.h> const int MAXN = 5e5 + 5; const int MAXP = 3e7 + 5; using namespace std; typedef long long ll; template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } struct SegmentTree { struct Node { int lc, rc; int sum; } a[MAXP]; int size, depth; void init(int x) { size = 0; depth = x; } int modify(int root, unsigned pos, int d, int depth) { a[++size] = a[root]; a[size].sum += d; int ans = size; if (depth == -1) return ans; unsigned tmp = 1u << depth; if (tmp & pos) a[ans].rc = modify(a[root].rc, pos, d, depth - 1); else a[ans].lc = modify(a[root].lc, pos, d, depth - 1); return ans; } int modify(int root, unsigned pos, int d) { if (a[root].sum || d >= 1) return modify(root, pos, d, depth); else return root; } unsigned query(int root, int val, int depth) { if (depth == -1) return 0; unsigned tmp = 1u << depth; if (val & tmp) { if (a[a[root].lc].sum) return query(a[root].lc, val, depth - 1) + tmp; else return query(a[root].rc, val, depth - 1); } else { if (a[a[root].rc].sum) return query(a[root].rc, val, depth - 1) + tmp; else return query(a[root].lc, val, depth - 1); } } unsigned query(int root, unsigned val) { if (a[root].sum) return query(root, val, depth); else return 0; } } ST; ll ans; int root[MAXN]; unsigned s[MAXN]; priority_queue <pair <unsigned, int> > Heap; int main() { int n, k; read(n), read(k); ST.init(31); for (int i = 1; i <= n; i++) { unsigned x; read(x); s[i] = s[i - 1] ^ x; root[i] = ST.modify(root[i - 1], s[i - 1], 1); Heap.push(make_pair(ST.query(root[i], s[i]), i)); } for (int i = 1; i <= k; i++) { unsigned inc = Heap.top().first; ans += inc; int pos = Heap.top().second; Heap.pop(); root[pos] = ST.modify(root[pos], s[pos] ^ inc, -1); Heap.push(make_pair(ST.query(root[pos], s[pos]), pos)); } cout << ans << endl; return 0; }