表單form初始
阿新 • • 發佈:2021-10-28
題目大意
給定 \(n\) 個數的序列 \(a\)。
\(m\) 次操作。
操作有一種:
l r
:求 \(a_l\sim a_r\) 中,出現偶數次的數的異或和。
\(1\le n,m\le 10^6\),\(1\le a_i\le 10^9\)。
解題思路
嘗試轉換題意,手玩 可知,出現偶數次的數的異或和 \(=\) 出現過數(出現多次算一個)的異或和 \(\operatorname{xor}\) 所有數的異或和。
所有數異或和可以用字首和維護。
出現過數(出現多次算一個)的異或和可以線性記錄每一個數它之前出現過的位置 \(pre\)。
若他是第一個出現的數,他之前出現過的位置為 \(0\)。
然後用樹狀陣列維護即可。
即每次將這個點 \(x\) 加上 \(a[x]\),並將 \(pre[x]\) 也加上 \(a[x]\)。
那麼若一個數在這段區間裡出現過,那麼在樹狀陣列中他只 \(\operatorname{xor}\) 過奇數次。
詢問可以離線考慮,按右端點排序,可以達到 \(\mathcal{O}(n \log n)\) 的時間複雜度。
具體參考程式碼。
CODE
#include <bits/stdc++.h> using namespace std; inline int read() { int x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } inline void write(int x) { if(x < 0) { putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } const int _ = 1000007; int c[_]; int n, m; int a[_]; int sum[_]; int pre[_]; map<int, int> d; int ans[_]; inline int lowbit(int x) { return x & -x; } inline void update(int x, int val) { if(x == 0) return; for(int i = x; i <= n; i += lowbit(i)) c[i] ^= val; } inline int query(int x) { if(x == 0) return 0; int res = 0; for(int i = x; i; i -= lowbit(i)) res ^= c[i]; return res; } struct abc { int l, r, id; } q[_]; bool cmp(abc a, abc b) { return a.r < b.r; } signed main() { n = read(); for(int i = 1; i <= n; ++i) { a[i] = read(); sum[i] = sum[i - 1] ^ a[i]; pre[i] = d[a[i]]; d[a[i]] = i; } m = read(); for(int i = 1; i <= m; ++i) { q[i].l = read(); q[i].r = read(); q[i].id = i; } sort(q + 1, q + m + 1, cmp); int tot = 0; for(int i = 1; i <= m; i++) { while(tot < q[i].r) { tot++; update(tot, a[tot]); update(pre[tot], a[pre[tot]]); } ans[q[i].id] = query(q[i].r) ^ query(q[i].l - 1) ^ sum[q[i].r] ^ sum[q[i].l - 1]; } for(int i = 1; i <= m; ++i) cout << ans[i] << "\n"; return 0; }
本文來自部落格園,作者:蒟蒻orz,轉載請註明原文連結:https://www.cnblogs.com/orzz/p/15502414.html