偶数次子区间个数
题意
有序列 \(S(n \leq 10^5, S_i \leq 10^6)\), 问区间 \([l, r]\) 内满足每个数出现偶数次的子区间个数。
转化
想到区间出现每个数偶数次,那么异或和一定为 0。
但是异或和为 0 的区间每个数不一定出现偶数个。
于是对相同的值赋一个 \([0, 2^{64})\) 内随机的值。
这样出现冲突的概率很低。
莫队
剩下问题转化为前缀异或,找相同异或值的数即可。
代码
#include
using namespace std;
using ll = long long;
const int MAXN = 1000010;
const int INF = 0x7fffffff;
const int mod = 1000000007;
template
void Read(T &x) {
x = 0; T f = 1; char a = getchar();
for(; a < '0' || '9' < a; a = getchar()) if (a == '-') f = -f;
for(; '0' <= a && a <= '9'; a = getchar()) x = (x * 10) + (a ^ 48);
x *= f;
}
int n, m, len;
int a[MAXN], cnt[MAXN];
ll mp[MAXN], Xor[MAXN], b[MAXN];
struct ques {
int l, r, id;
}q[MAXN];
int ans[MAXN], belong[MAXN];
int main() {
mt19937 rd(1145141919);
cin >> n;
for (int i = 1; i < MAXN; i ++)
mp[i] = rd() % (1ll << 63);
int siz = sqrt(n);
for (int i = 1; i <= n; i ++) {
cin >> a[i];
Xor[i] = Xor[i - 1] ^ mp[a[i]];
b[++ len] = Xor[i];
belong[i] = (i - 1) / siz + 1;
}
b[++ len] = 0;
a[0] = 1;
sort(b + 1, b + len + 1);
len = unique(b + 1, b + len + 1) - b - 1;
for (int i = 1; i <= n; i ++)
a[i] = lower_bound(b + 1, b + len + 1, Xor[i]) - b;
cin >> m;
for (int i = 1; i <= m; i ++)
cin >> q[i].l >> q[i].r, q[i].l --, q[i].id = i;
sort (q + 1, q + m + 1, [](ques x, ques y) {
if (belong[x.l] ^ belong[y.l]) return belong[x.l] < belong[y.l];
if (belong[x.l] ^ 1) return x.r < y.r;
return x.r > y.r;
});
int l = 0, r = -1, sum = 0;
for (int i = 1; i <= m; i ++) {
while (l > q[i].l) sum += cnt[a[-- l]] ++;
while (r < q[i].r) sum += cnt[a[++ r]] ++;
while (l < q[i].l) sum -= -- cnt[a[l ++]];
while (r > q[i].r) sum -= -- cnt[a[r --]];
ans[q[i].id] = sum;
}
for (int i = 1; i <= m; i ++)
cout << ans[i] << endl;
return 0;
}