[Codeforces799F] [哈希] Beautiful fountains rows

23 篇文章 0 订阅
15 篇文章 0 订阅

%%%Manchery

给每个区间随机一个权值,这样每个位置被哪些区间覆盖奇数次就可以用区间权值的xor值表示,假设为x,一个区间被哪些区间覆盖也可以用xor值表示,假设为y
那么满足x=y的区间就是符合条件的区间

前缀和搞一搞,map记一记就好啦

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#define N 200010

using namespace std;

typedef unsigned long long ull;
typedef pair<ull,ull> paru;

int n,m;
long long ans;
int l[N],r[N],num[N];
ull p1[N],p2[N];
vector<ull> s1[N],t1[N],s2[N],t2[N];
map<paru,long long> M,S;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void rea(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline long long calc(int x){
  return 1ll*(x+1)*x*x/2-1ll*(x-1)*x/2-1ll*x*(x-1)*(2*x-1)/6;
}

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  rea(n); rea(m);
  for(int i=1;i<=n;i++){
    rea(l[i]); rea(r[i]);
    ull hash1=1ULL*rand()*rand()*rand(),hash2=1ULL*rand()*rand()*rand();
    s1[l[i]].push_back(hash1); s2[l[i]].push_back(hash2);
    t1[r[i]].push_back(hash1); t2[r[i]].push_back(hash2);
    p1[l[i]]^=hash1; p1[r[i]+1]^=hash1;
    p2[l[i]]^=hash2; p2[r[i]+1]^=hash2;
    num[l[i]]++; num[r[i]+1]--;
  }
  for(int i=1;i<=m;i++) p1[i]^=p1[i-1],p2[i]^=p2[i-1];
  for(int i=1;i<=m;i++) p1[i]^=p1[i-1],p2[i]^=p2[i-1];
  ull a1=0,b1=0,a2=0,b2=0;
  M[paru(0,0)]=1;
  for(int i=1;i<=m;i++){
    for(int x=0;x<s1[i].size();x++) a1^=s1[i][x],a2^=s2[i][x];
    ans+=M[paru(a1^p1[i],a2^p2[i])]*i-S[paru(a1^p1[i],a2^p2[i])];
    for(int x=0;x<t1[i].size();x++) b1^=t1[i][x],b2^=t2[i][x];
    M[paru(b1^p1[i],b2^p2[i])]++; S[paru(b1^p1[i],b2^p2[i])]+=i;
  }
  for(int i=1;i<=m;i++) num[i]+=num[i-1];
  for(int i=1,j;i<=m;i=j+1){
    j=i;
    while(j<=m&&num[j]==0) j++;
    j--;
    if(j<i) j=i;
    else ans-=calc(j-i+1);
  }
  printf("%I64d\n",ans);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值