XOR of Suffix Sums
题意
有一个初始为空的序列 aaa,有 qqq 次操作,每次操作 (t,v)(t, v)(t,v) 会将 aaa 的最后 ttt 个数字删除,并将元素 vvv 添加到 aaa 的末尾
对于每次操作完后的数组 aaa,输出其每一个位置的后缀和的异或和
即 s1⨁s2⨁...⨁sns_1 \bigoplus s_2 \bigoplus ... \bigoplus s_ns1⨁s2⨁...⨁sn,答案对 2212^{21}221 取模
思路
记当前序列为 a1,a2,...,ana_1, a_2, ..., a_na1,a2,...,an,定义一个前缀和数组 ppp,我们注意到:在操作过程中,只有后缀一直在变化,而前缀和保持不变。因此我们把后缀转为前缀,这样子就可以快速修改信息
对于一个后缀 [i,n][i, n][i,n],其值即为 pn−pi−1p_n - p_{i - 1}pn−pi−1,即 pn+(−pi−1)p_n + (-p_{i - 1})pn+(−pi−1)
我们可以分别计算答案的每一位,由于答案对 2212^{21}221 取模,因此只有低 212121 位有效。
对于当前位 b(0≤b<21)b( 0 \leq b < 21)b(0≤b<21),我们只需要统计是否有奇数个后缀和满足这一位为 111即可
注意到 ∀i∈[1,n], pn+(−pi−1)\forall i \in [1, n], \;\; p_n + (-p_{i - 1})∀i∈[1,n],pn+(−pi−1) 的第一个变量是不变的,变化的只有后面那个变量
如何统计?
我们通过取模转换一下值域,即要求 pn+(−pi−1)mod 2b+1≥2bp_n + (-p_{i - 1}) \mod 2^{b+1} \geq 2^bpn+(−pi−1)mod2b+1≥2b 的 iii 的数量
不难发现,通过上述转换,值域变得很小,我们就可以在树状数组上快速查询满足条件的 −pi−1-p_{i - 1}−pi−1 数量
我们之前已经插入了 (−p0mod 2b+1)→(−pn−1mod 2b+1)(-p_0 \mod 2^{b + 1}) \rarr (-p_{n - 1} \mod 2^{b + 1})(−p0mod2b+1)→(−pn−1mod2b+1),而我们现在需要求出一个区间,使得 pnmod 2b+1p_n \mod 2^{b + 1}pnmod2b+1 加上这个区间内任何一个数后,最终值会落在 [2b,2b+1−1][2^b, 2^{b + 1} - 1][2b,2b+1−1] 内,其实这可以利用取模的性质(周期性)来计算了。
只需要分两种情况考虑一下即可
时间复杂度:O(nlog2Mod+Mod)O(n \log^2 Mod + Mod)O(nlog2Mod+Mod)
#include<bits/stdc++.h>
#define fore(i,l,r) for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
#define ALL(v) v.begin(), v.end()
#define Debug(x, ed) std::cerr << #x << " = " << x << ed;
const int INF=0x3f3f3f3f;
const long long INFLL=1e18;
typedef long long ll;
struct FenWick{
std::vector<int> fen;
int n;
void init(int n){
fen.assign(n + 5, 0);
this -> n = n;
}
void update(int p, int d){
for(int i = p; i <= n; i += i & -i)
fen[i] += d;
}
int query(int p){
int res = 0;
while(p > 0){
res += fen[p];
p -= p & -p;
}
return res;
}
};
const int N = 500005;
const int B = 21;
const int D = 1; //偏移量,由于值域包括0
FenWick Fen[B];
ll p[N];
void update(ll x, int d){
fore(b, 0, B){
int val = x & ((1 << b + 1) - 1);
Fen[b].update(val + D, d);
}
}
int query(ll x, int n){
int res = 0;
fore(b, 0, B){
int val = x & ((1 << b + 1) - 1); //对 2 ^ (b + 1) 取模
int cnt = 0;
if(val <= (1 << b))
cnt = Fen[b].query(D + (1 << b + 1) - 1 - val) - Fen[b].query(D + (1 << b) - val - 1);
else
cnt = n - Fen[b].query(D + (3 << b) - 1 - val) - Fen[b].query(D + (2 << b) - val - 1);
if(cnt & 1) res += 1 << b; //这一位是奇数
}
return res;
}
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
fore(b, 0, B) Fen[b].init(1 << b + 1);
int n = 0, q;
std::cin >> q;
while(q--){
int t, v;
std::cin >> t >> v;
while(t--){
update(-p[n - 1], -1);
--n;
}
++n;
p[n] = p[n - 1] + v;
update(-p[n - 1], 1);
std::cout << query(p[n], n) << endl;
}
return 0;
}