题目大概意思是给n种球,长为m的数轴,给出n个区间,区间 [ l i , r i ] [l_{i},r_{i}] [li,ri]每个点都放上第i种球,让你求出区间长度之和,要求区间内有球,且球的个数为奇数。
这个题如果直接用数据结构我真不会,看网上的都是随机化,给每种球随机一个值,那么我们可以知道,某个区间如果符合要求,那么这个区间每个点的异或值应该
=
=
==
==这个区间出现的数的异或值。
那么前一个我们可以用前缀和来做,后一个我们还是用前缀和。
首先
p
r
e
pre
pre数组表示异或前缀和
a
a
a数组表示每个点的值
A
A
A数组表示每个区间以i为左端点出现的数的异或值
d
d
d数组表示0~i出现过的数的异或值
所以区间
[
L
,
R
]
[L, R]
[L,R]如果符合条件那么他就应该满足以下条件
s
u
m
[
R
]
⊕
s
u
m
[
L
−
1
]
=
=
d
[
R
]
⊕
d
[
L
−
1
]
sum[R]\oplus{sum[L - 1]} == d[R]\oplus{d[L - 1]}
sum[R]⊕sum[L−1]==d[R]⊕d[L−1] 其中
d
[
L
−
1
]
d[L - 1]
d[L−1] 可以更换为
d
[
L
]
⊕
a
[
L
]
d[L]\oplus{a[L]}
d[L]⊕a[L](这里的正确性有待考证)移相可得
s
u
m
[
R
]
⊕
s
u
m
[
L
]
=
=
d
[
R
]
⊕
d
[
L
]
=
>
s
u
m
[
R
]
⊕
d
[
R
]
=
s
u
m
[
L
]
⊕
d
[
L
]
sum[R]\oplus{sum[L]} == d[R]\oplus{d[L]} => sum[R]\oplus{d[R]} = sum[L]\oplus{d[L]}
sum[R]⊕sum[L]==d[R]⊕d[L]=>sum[R]⊕d[R]=sum[L]⊕d[L]用map记录右边的值,这样就可以找到符合上述等式几个点,这几个点中任意两点都符合上式,也就是要求的区间,求和的话有一个小技巧我们求出(i - 1)的和,将每个点都先乘i再减去前方求的和就是当前点到前方任意一点之间的距离之和。
最后减去空区间,空区间每加入一个点就相当于多加了一个等差数列。
代码:
#include <bits/stdc++.h>
#define solve(x) x*(x + 1)/2
using namespace std;
typedef unsigned long long ull;
const int maxn = 2e5 + 10;
ull pre[maxn],a[maxn];
ull A[maxn];
ull d[maxn];
map<ull, long long > mp, mp1;
int main()
{
srand(998244353);
int n,m;
cin >> n >> m;
for(int i = 0; i < n; i ++){
int x,y;
cin >> x >> y;
ull w=(ull)rand()*rand()*rand()+(ull)rand()*rand();
a[x]^= w;
a[y + 1] ^= w;
A[x] ^= w;
}
for(int i = 1; i <= m; i ++){
a[i] ^= a[i - 1];
d[i] = d[i - 1] ^ A[i];
pre[i] = pre[i - 1] ^ a[i];
}
ull ans = 0;
for(int i = 1; i <= m; i ++){
ull x = pre[i]^d[i];
mp[x] ++, mp1[x] = mp1[x] + i - 1;
ans += mp[x]*i - mp1[x];
}
for(int i = 1, j = 0; i <= m; i ++){
if(a[i] == 0) ans -= solve(ull(i - j));
else j = i;
}
cout << ans << endl;
}