找到这道题的时候,我啪的一下啊!很快啊!我想到了暴力将每个数搞到集合里的做法,然后每个集合有一个实际序列 $[l_i,r_i]$。
但这样就被偷袭了!
考虑只需要集合整个的权值,我们直接开个差分数组搞下就好了。然后长度和就往块内 $hash$ 顺便记个集合下标。
这题不同于这题的原因是这题的区间是连续的。所以可以不用分块维护。
那么,显然我们要维护异或前缀和及区间出现过的数的异或前缀和。
但既然区间是连续的,假如这段区间长度偶数,那么异或起来为 $0$,又因为 $0$ 肯定比较好判断,所以我们可以让这段区间的长度 $-1$。
即修改作用在 $[x+1,y]$,假如查询 $[x,y]$ ,那么相当于查询 $[x+1,y]$ 的异或和是否为 $0$。
那么为什么 $loj$ 那题不能这样做的,主要原因还是因为颜色不连续,我认为。
这题中对于空集的话可以最后在减去贡献。
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cmath> #include <queue> #include <map> #include <ctime> #define ll long long #define ull unsigned ll 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); map<ull,pair<int,ull> >mp; ull ans,cnt[N],s[N],nmsl[N]; int n,m; ull get_rand() { return 1llu*RAND_MAX*RAND_MAX*RAND_MAX*rand()+1llu*RAND_MAX*rand()+1llu*rand()*rand()+1llu*RAND_MAX*rand()+1llu*rand(); } signed main() { srand(time(NULL)*114); int x,y; n=rd(); m=rd(); for(int i=1;i<=n;i++) { x=rd(); y=rd(); ++cnt[x]; --cnt[y+1]; ull qwq=get_rand(); s[x+1]^=qwq; s[y+1]^=qwq; } for(int i=1;i<=m;i++) s[i]^=s[i-1]; for(int i=1;i<=m;i++) s[i]^=s[i-1]; for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(int i=1;i<=m;i++) { pair<int,ull>qwq=mp[s[i]]; qwq.first++; qwq.second+=i-1; mp[s[i]]=qwq; ans+=1llu*qwq.first*i-qwq.second; } for(int i=1;i<=m;i++) { if(!cnt[i]) nmsl[i]=nmsl[i-1]+1; else nmsl[i]=0; } for(int i=1;i<=m;i++) ans-=nmsl[i]*(nmsl[i]+1)/2; cout<<ans; }