http://codeforces.com/contest/703/problem/D
Summary:
Given array a[i] for N <= 10^6 integers, and M <= 10^6 queries (L, R): collect all integers in a[L..R] that occur even number of times, and compute their XOR. E.g. for a = {1, 2, 2, 3, 4, 4}, query (2, 7) returns 2 XOR 4 = 6. If no such element in a particular query, return 0.
Solution:
The solution employs interesting segment tree update technique. The observation is that the answer to the query (L, R) can be computed as the XOR of:
1. XOR of all elements in L to R (where each integer that occurs even number of times will cancel each other out) with
2. XOR of all distinct elements in L to R.
Part 1 is trivial, part 2 is the hard part. The idea is to process the queries in prefix order. Sort the queries in increasing R order. For each integers x that we will encounter from left to right while we are processing the queries, we keep track of the last_pos[x] the right most position where we have seen this number.
Hence if we want to find the XOR of all distinct integers from L to R, all we need to do is to XOR all integers x on which the last_pos[x] is >= L. By maintaining a segment tree, we can compute and update the XOR in O(log N). For each new position of x, the mechanic of the update will be: first update segment tree at old position last_pos[x] to 0, then update last_pos[x] to newest last position, and finally update the segment tree at new last_pos[x] to x.
Implementation:
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <map> #include <utility> using namespace std; struct Query { int left; int right; int id; }; int n; map<int,int> last_pos; vector<int> segtree; // Containing XOR of distinct elements from [L, R]. void UpdateSegtree(int i, int val, int p=1, int L=0, int R=n-1) { if (R < i || i < L) return; if (L == R && L == i) { segtree[p] = val; return; } int M = (L+R)/2; UpdateSegtree(i, val, p*2, L, M); UpdateSegtree(i, val, p*2+1, M+1, R); segtree[p] = segtree[2*p] ^ segtree[2*p+1]; } int RangeQuery(int S, int T, int p=1, int L=0, int R=n-1) { if (R<S || T<L) return 0; if (S <= L && R <= T) return segtree[p]; int M = (L+R)/2; return RangeQuery(S, T, p*2, L, M) ^ RangeQuery(S, T, p*2+1, M+1, R); } int main(){ scanf("%d",&n); vector<int> a(n, 0); vector<int> xor_sum(n, 0); for (int i=0;i<n;++i){ scanf("%d",&a[i]); xor_sum[i] = a[i]; if (i > 0) xor_sum[i] ^= xor_sum[i-1]; } segtree.resize(4*n, 0); int m; vector<Query> queries; scanf("%d",&m); int l,r; for (int i=0;i<m;++i){ scanf("%d%d",&l,&r); l--; r--; queries.push_back({l, r, i}); } sort(queries.begin(), queries.end(), [](const Query& L, const Query& R) { return L.right < R.right; }); vector<int> ans(m, 0); int last_index = 0; for (int i=0;i<m;++i){ l = queries[i].left; r = queries[i].right; while (last_index <= r) { auto it = last_pos.find(a[last_index]); if (it != last_pos.end()) { UpdateSegtree(it->second, 0); } last_pos[a[last_index]] = last_index; UpdateSegtree(last_index, a[last_index]); ++last_index; } ans[queries[i].id] = xor_sum[r] ^ (l>0 ? xor_sum[l-1] : 0) ^ RangeQuery(l, r); } for (int i = 0; i < m; ++i) { printf("%d\n",ans[i]); } return 0; }
Corollary: to compute property of distinct integers in (L, R), we can service the queries in prefix order (increasing R ordering) and extend the prefix from left to right, while keeping track of each last position of the integers along the way.
acheter arme
ReplyDeletepistool kopen
m16
m1 garand
ar15
ak47
sig sauer p320
cz shadow 2
cz75
glock 45