题目梗概
有
n
个不同的数字,每个数字只出现在
求所有满足要求的区间的长度和。
要求:出现在该区间的所有数字的个数必须为奇数,且必须有数字存在。
解题思路
考虑一个区间如何才能满足要求。
将每个数字赋上一个
(263−1,0]
的随机值。
这个区间所有数字的异或值再异或上这个区间出现过的数字,如果等于0,那么这个区间满足要求。
对于区间所有数字的异或值构造前缀异或和数组
P[]
即可。
考虑
[L,R]
区间出现过的数字的异或值。
一个数字
i
在
!(y[i]<L||x[i]>R)=(y[i]>=Landx[i]<=R)
,满足条件的所有数字就是满足
x[i]<=R
的数字
XOR
满足
(y[i]<Landx[i]<=R)
的数字。
观察 (y[i]<Landx[i]<=R) ,发现如果前一项满足后一项显然也满足,所以这个条件变为 y[i]<L 。
我们分别开数组
s[],t[]
分别构造满足
x[i]<=R,y[i]<L
的异或和,数组的构造显然是线性的。
通过以上变换题目初始条件变为满足
P[R]
^
P[L−1]==s[R]
^
t[L]
移项得
t[L]
^
P[L−1]==s[R]
^
P[R]
把前项压进一个map里就可以了。
Ps:本人脸丑,不得不双hash。
#include<map>
#include<vector>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
typedef pair<LL,LL> jz;
const int maxn=200005;
int n,m;
inline int _read(){
int num=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();
return num;
}
map<jz,LL> G,S;
vector<int> L[maxn],R[maxn];
LL a[maxn],b[maxn],p1[maxn],p2[maxn],ans;
int x[maxn],y[maxn],num[maxn];
LL calc(LL x){return (x+1)*x*(x+1)/2-x*(x+1)*(2*x+1)/6;}
int main(){
n=_read();m=_read();
for (int i=1;i<=n;i++){
x[i]=_read(),y[i]=_read();
L[x[i]].push_back(i);R[y[i]].push_back(i);
a[i]=(LL)rand()*rand()*rand()*rand();
b[i]=(LL)rand()*rand()*rand()*rand();
p1[x[i]]^=a[i];p1[y[i]+1]^=a[i];
p2[x[i]]^=b[i];p2[y[i]+1]^=b[i];
num[x[i]]++;num[y[i]+1]--;
}
for (int k=0;k<2;k++) for (int i=1;i<=m;i++) p1[i]^=p1[i-1],p2[i]^=p2[i-1];
G[jz(0,0)]=1;
LL s1=0,s2=0,t1=0,t2=0;
for (int i=1;i<=m;i++){
for (int j=0;j<L[i].size();j++) s1^=a[L[i][j]],s2^=b[L[i][j]];
ans+=G[jz(s1^p1[i],s2^p2[i])]*i-S[jz(s1^p1[i],s2^p2[i])];
for (int j=0;j<R[i].size();j++) t1^=a[R[i][j]],t2^=b[R[i][j]];
G[jz(t1^p1[i],t2^p2[i])]++;S[jz(t1^p1[i],t2^p2[i])]+=i;
}
for (int i=1;i<=m;i++) num[i]+=num[i-1];
int i=1,j;
while(i<=m){
j=i;
while(j<=m&&num[j]==0) j++;
ans-=calc(j-i);i=j+1;
}
printf("%lld\n",ans);
return 0;
}