X or What?
符號約定:
- $\xor$ 表示異或。
- popcount($x$) 表示非負整數 $x$ 的二進制表示里數字 1 出現的次數。例如,$13 = 1101_2$,則 popcount(13) = 4。
注意到,popcount($a \xor b$) = popcount($a$) + popcount($b$) - 2 * number of positions both $a$ and $b$ are set。
因此,popcount($a \xor b$) 的奇偶性 = (popcount($a$) + popcount($b$)) 的奇偶性。
區間 $[L, R]$ 的異或和的 popcount 為偶數 $\iff$ $L - 1, R$ 這兩個前綴的異或和的 popcount 同奇偶。
分別考慮異或和的 popcount 為奇數的前綴、異或和的 popcount 為偶數的前綴。
改變 $A_p$ 對答案的影響:
若 $A_p$ 的 popcount 的奇偶性不變,則答案亦不變,否則 $p, p+1, \dots, n - 1$ 這些前綴的異或和的 popcount 的奇偶性翻轉。
解法 1
用線段樹維護前綴的異或和的 popcount 的奇偶性。
支持查詢:
- 異或和的 popcount 為偶數的前綴最后一次出現的位置。
- 異或和的 popcount 為奇數的前綴第一次/最后一次出現的位置。
bool bit_even(int x) {return (__builtin_popcount(x) & 1) == 0;
}struct node {int n[2];int flipped;void flip() {swap(n[0], n[1]);flipped ^= 1;}
};
const int N = 100005;
node seg[4 * N];int sum[N];
void push_up(int i) {int l = i * 2, r = l + 1;for (int j = 0; j < 2; j++) {seg[i].n[j] = seg[l].n[j] + seg[r].n[j];}
}void build (int i, int l, int r) {seg[i].flipped = 0;if (l == r) {seg[i].n[0] = bit_even(sum[l]);seg[i].n[1] = 1 - seg[i].n[0];return;}int mid = (l + r) / 2;build(i * 2, l, mid);build(i * 2 + 1, mid + 1, r);push_up(i);
}void push_down(int i) {if (seg[i].flipped) {int l = i * 2, r = i * 2 + 1;seg[l].flip();seg[r].flip();seg[i].flipped = 0;}
}int find_first(int v, int i, int l, int r) {if (seg[i].n[v] == 0) return r + 1;if (l == r) return l;push_down(i);int mid = (l + r) / 2;int res = find_first(v, i * 2, l, mid);if (res <= mid) {return res;}return find_first(v, i * 2 + 1, mid + 1, r);
}int find_last(int v, int i, int l, int r) {if (seg[i].n[v] == 0) return l - 1;if (l == r) return l;push_down(i);int mid = (l + r) / 2;int res = find_last(v, i * 2 + 1, mid + 1, r);if (res > mid) {return res;}return find_last(v, i * 2, l, mid);
}void flip(int i, int l, int r, int ql, int qr) {if (ql > r || qr < l) return;if (ql <= l && r <= qr) {seg[i].flip();return;}int mid = (l + r) / 2;push_down(i);flip(i * 2, l, mid, ql, qr);flip(i * 2 + 1, mid + 1, r, ql, qr);push_up(i);
}int main() {
#ifdef LOCALifstream in("main.in");cin.rdbuf(in.rdbuf());
#endifint T; cin >> T;for (int cas = 1; cas <= T; ++cas) {cout << "Case #" << cas << ":";int n, q; cin >> n >> q;vector<int> a(n + 1);for (int i = 1; i <= n; i++) {cin >> a[i];sum[i] = sum[i - 1] ^ a[i];}build(1, 1, n);while (q--) {int p, v;cin >> p >> v;++p;if (bit_even(v) != bit_even(a[p])) {flip(1, 1, n, p, n);}a[p] = v;cout << " " << max(find_last(0, 1, 1, n), find_last(1, 1, 1, n) - find_first(1, 1, 1, n));}cout << endl;}return 0;
}
轉載于:https://www.cnblogs.com/Patt/p/11260053.html
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的Kick Start 2019 Round D的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。