CF799F Beautiful fountains rows

找到这道题的时候,我啪的一下啊!很快啊!我想到了暴力将每个数搞到集合里的做法,然后每个集合有一个实际序列 $[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;
}

  

posted @ 2021-08-18 17:06  FxorG  阅读(138)  评论(0编辑  收藏  举报