upt:由于是异或,正确性不一定能保证。可以考虑对每个权值随机赋值加强正确性。
首先有个性质,假如这个区间合法,那么这个区间的异或和等于这个区间出现过的数的异或和。
出现过的数自然想到 HH 的项链,考虑记 $las$,然后一个数只对 $[las_{a[i]}+1,i]$ 有贡献。
记 $ s_i=v[1] xor v[2] xor ... v[i]$ 即前缀异或和。
$sum1$ 为区间出现过的数的异或和。
那么,答案就是 $s_y xor s_{x-1} = sum1_{x->y}$,转换下 $ s_y=sum1{x->y} xor s_{x-1}$,即找多少个 $xor$ 起来与 $s_y$ 相等的。
如何维护 $sum1$ 呢,对于一个数 $a[i]$,它对左端点影响区间是 $[las_{a[i]}+1,i]$(因为我们查找就是找 $x$,注意是端点不是区间,区间的话需要再抵消上一次的贡献),我们要让这整个端点区间异或上 $val[a[i]]$(因为查找就是找 $[x,y]$ $y$ 是当前枚举的,$xin [1,y]$)。对于 $s_{x-1}$ 我们可以考虑就是它本来的权值。
考虑 $s_y$ 可能很大,需要用 $hash$ 查找,发现可以用分块,对于每个块开一个 $hash$ 表,整个序列初始权值为 $s_{i-1}$,然后其他操作显然。
我的代码应该是最劣解 /cy
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <ctime>
#define ll long long
using namespace std;
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
ll lrd() {
ll f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
const int N=(int)(2e5+5),M=(int)(1e6+5),B=500,mod=4991;
ll s[N],val[M],id[N],L[B],R[B],tag[B],Bsum[N];
int a[N],las[M],n,bl=450;
struct HASH {
struct node {
int cnt,nex; ll val;
}H[mod+2];
int head[mod+2],tot;
void clear() {
tot=0; memset(head,0,sizeof(head));
}
int Find(ll x) {
for(int i=head[x&mod];i;i=H[i].nex) if(H[i].val==x) return i;
return -1;
}
int query(ll x) {
int h=Find(x);
if(~h) return H[h].cnt;
return 0;
}
void ins(ll x) {
int h=Find(x);
if(~h) ++H[h].cnt;
else {
H[++tot].cnt=1; H[tot].nex=head[x&mod]; H[tot].val=x; head[x&mod]=tot;
}
}
}Hash[B];
ll get_rand() {
return (1ll*rand()<<31|rand());
}
void build(int x) {
Hash[x].clear();
for(int i=L[x];i<=R[x];i++) Bsum[i]^=tag[x],Hash[x].ins(Bsum[i]); tag[x]=0;
}
void update(int l,int r,ll v) {
if(id[l]==id[r]) {
for(int i=l;i<=r;i++) Bsum[i]^=v;
build(id[l]);
} else {
for(int i=l;i<=R[id[l]];i++) Bsum[i]^=v;
for(int i=L[id[r]];i<=r;i++) Bsum[i]^=v;
build(id[l]); build(id[r]);
for(int i=id[l]+1;i<id[r];i++) tag[i]^=v;
}
}
int query(int l,int r,ll v) {
ll res=0;
if(id[l]==id[r]) {
build(id[l]); for(int i=l;i<=r;i++) res+=(Bsum[i]==v);
} else {
build(id[l]); build(id[r]);
for(int i=l;i<=R[id[l]];i++) res+=(Bsum[i]==v);
for(int i=L[id[r]];i<=r;i++) res+=(Bsum[i]==v);
for(int i=id[l]+1;i<id[r];i++) res+=Hash[i].query((v^tag[i]));
}
return res;
}
int main() {
// freopen("odd5.in","r",stdin);
srand(time(0));
int mx=0; n=rd();
for(int i=1;i<=n;i++) a[i]=rd(),id[i]=(i-1)/bl+1,mx=max(mx,a[i]);
for(int i=0;i<=mx;i++) val[i]=get_rand();
for(int i=1;i<=id[n];i++) L[i]=(i-1)*bl+1,R[i]=i*bl; R[id[n]]=n;
for(int i=1;i<=id[n];i++) build(i);
for(int i=1;i<=n;i++) Bsum[i]=s[i-1],s[i]=(s[i-1]^val[a[i]]);
ll ans=0;
for(int i=1;i<=n;i++) {
update(las[a[i]]+1,i,val[a[i]]); las[a[i]]=i;
ans+=query(1,i,s[i]);
}
printf("%lld",ans);
}