题目大意
给出序列a,
如果一个子区间,满足每个数都只出现了奇数次,那么它是个好区间。
求好区间数的个数。
n<=2*10^5
思路
由于出现奇数次,可以想到就是用随机数作为值,
区间的值xor=区间出现的值xor,
然后得到区间的值xor xor 区间出现的值xor=0
考虑已经维护了对于位置i,[i,r]区间的值
如果r变成r+1
那么1~r+1 异或上w[a[r+1]],last[a[r+1]]+1~r+1异或上w[a[r+1]]
(last[i]为值i上次出现位置,没有为0)
然后就是1~last[a[r+1]]异或上w[a[r+1]]
题目就变为,区间xor,询问0的个数
可以用分块+hash表解决
时间复杂度O(n*sqrt{n})
代码
#include<bits/stdc++.h>
#define fo(i,x,y) for(int i = x,_b = y; i <= _b; i ++)
#define ff(i,x,y) for(int i = x,_b = y; i < _b; i ++)
#define fd(i,x,y) for(int i = x,_b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
#define ul unsigned long long
ul rx = 1e9 + 7;
ll rand(ll x,ll y) {
rx *= 998244353;
return rx % (y - x + 1) + x;
}
const int M = 1e6 + 5;
ll rv[M];
const int N = 2e5 + 5;
int n;
ll a[N],s[N];
int la[N],ed[M];
void Init() {
fo(i,0,1e6) rv[i] = rand(1,1ll << 60);
scanf("%d",&n);
fo(i,1,n) {
scanf("%lld",&a[i]);
la[i] = ed[a[i]];
ed[a[i]] = i;
a[i] = rv[a[i]];
s[i] = s[i - 1] ^ a[i];
}
}
namespace yjy {
const int blo = 400;
const int C = N / blo + 5;
const int M = 20007;
struct nod {
int fi[M],d[blo + 5],d0;
int nt[blo + 5],cnt[blo + 5],td;
ll h[blo + 5];
void _new() {
fo(i,1,td) cnt[i] = 0;
fo(i,1,d0) fi[d[i]] = 0;
td = d0 = 0;
}
int& operator [] (ll n) {
int y = n % M;
for(int p = fi[y]; p; p = nt[p])
if(h[p] == n) return cnt[p];
if(fi[y] == 0) d[++ d0] = y;
nt[++ td] = fi[y],fi[y] = td,h[td] = n;
return cnt[td];
}
int find(ll n) {
int y = n % M;
for(int p = fi[y]; p; p = nt[p])
if(h[p] == n) return cnt[p];
return 0;
}
} c[C];
int id[N],id0,l[C],r[C];
ll v[N],lz[C];
void cg(int w) {
c[w]._new();
fo(i,l[w],r[w]) c[w][v[i]] ++;
}
void build() {
fo(i,1,n) {
if(i % blo == 1) l[++ id0] = i;
id[i] = id0; r[id0] = i;
}
fo(i,1,n) v[i] = s[i - 1];
fo(i,1,id0) cg(i);
}
void work_b(int x,int y,ll z) {
fo(i,x,y) v[i] ^= z;
cg(id[x]);
}
void work(int x,int y,ll z) {
if(id[x] == id[y]) return work_b(x,y,z);
work_b(x,r[id[x]],z); work_b(l[id[y]],y,z);
fo(i,id[x] + 1,id[y] - 1) lz[i] ^= z;
}
int qry_b(int x,int y,ll z) {
z ^= lz[id[x]]; int s = 0;
fo(i,x,y) s += (z == v[i]);
return s;
}
int qry(int x,int y,ll z) {
if(id[x] == id[y]) return qry_b(x,y,z);
int s = qry_b(x,r[id[x]],z) + qry_b(l[id[y]],y,z);
fo(i,id[x] + 1,id[y] - 1) s += c[i].find(z ^ lz[i]);
return s;
}
}
void solve() {
ll ans = 0;
fo(i,1,n) {
yjy :: work(la[i] + 1,i,a[i]);
ans += yjy :: qry(1,i,s[i]);
}
pp("%lld\n",ans);
}
int main() {
Init();
yjy :: build();
solve();
}