CF799F Beautiful fountains rows
CF799F Beautiful fountains rows
前言
感觉这3500还挺简单的?可能是因为年代久远的原因?
F Beautiful fountains rows
链接
https://codeforces.ml/contest/799/problem/F
题意
n行m列的01矩阵,对于第i行\(l_i<=x<=r_i\)的是1,其余都是0。数对(a,b)是好的,当且仅当第a列到第b列的矩阵有值为1的点且对于每一行在a到b之间的1的个数为0或奇数。求所有好数对的b-a+1的总和。\(1\leq n,m \leq 200000,1\leq l_i \leq r_i \leq m\) 。
题解
显然答案跟每一行的顺序无关。。
对于每一行,会导致一些数对(a.b)不好
根据数据结构的套路,这种时候肯定要枚举一个端点。。
于是从左向右枚举左端点a。
我们需要维护左端点固定时,右端点有哪些选择。
首先肯定要维护一下当前还剩哪些1区间需要考虑。
现在存在的1区间分两种:1.整段都在大于a的位置 2.从a开始就有1
然后考虑有哪些情况会导致一个数对不好。
1.全0,这个我们需要维护一下最近从几开始有1.
2.右端点的选择与第二类区间产生矛盾(偶数个1)
3.右端点的选择与第一类区间产生矛盾(偶数个1)
对于2,我们可以维护一下所有这类区间的终点,根据终点的奇偶分类讨论。然后对于3,根据起点,终点,长度的奇偶性各种讨论。。。
这样肯定是不好写的QAQ。。于是我们考虑再次离线的策略。
先讨论比较容易讨论的2 。并且将右端点分奇偶两类考虑。
与a同奇偶的右端点,只要不超过终点与a奇偶不同的区间就行。
与a不同奇偶的右端点,要不存在终点与a奇偶不同的区间,并且超过终点与a奇偶相同的区间。
显然这两个合法的部分都是连续的一段奇数或偶数。
然后把这些连续的段作为3的询问,看这些段里有多少能作为右端点。
3的区间会导致不好的右端点也需要讨论。
如果区间长度是偶数,说明区间后面的都不行。
然后区间内与区间左端L奇偶不同的也一定不行。
于是问题就变成了区间清零,区间询问的问题,搞个线段树就行了,要分奇偶询问。
\(Code\)
#include<bits/stdc++.h>
#define LL long long
#define LD long double
using namespace std;
const LL P=998244353;
const int N=3e5+10;
const int INF=1e9;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void print(LL x){
if(x>9) print(x/10);
putchar(x%10+'0');
}
void pls(LL &x,LL y){
x+=y;if(x>=P)x-=P;
}
int n,m;
struct Seg{
int l,r;
}a[N];
bool cmp(Seg x,Seg y){
return x.l<y.l;
}
multiset<int> ed[2];
multiset<int>::iterator it;
int cnt;
struct Query{
int st,op,l,r;
}q[N<<1];
struct Node{
int l,r;
LL num[2];
LL sum[2];
bool laz[2];
}d[N<<2];
#define ls id<<1
#define rs id<<1|1
void pushup(int id){
if(d[id].l==d[id].r) return;
d[id].num[0]=d[ls].num[0]+d[rs].num[0];
d[id].num[1]=d[ls].num[1]+d[rs].num[1];
d[id].sum[0]=d[ls].sum[0]+d[rs].sum[0];
d[id].sum[1]=d[ls].sum[1]+d[rs].sum[1];
return;
}
void pushdown(int id){
if(d[id].l==d[id].r) return;
if(!d[id].laz[0]){
d[id].laz[0]=1;
d[ls].num[0]=d[rs].num[0]=0;
d[ls].sum[0]=d[rs].sum[0]=0;
d[ls].laz[0]=d[rs].laz[0]=0;
}
if(!d[id].laz[1]){
d[id].laz[1]=1;
d[ls].num[1]=d[rs].num[1]=0;
d[ls].sum[1]=d[rs].sum[1]=0;
d[ls].laz[1]=d[rs].laz[1]=0;
}
return;
}
void build(int l,int r,int id){
d[id].l=l;d[id].r=r;
d[id].num[0]=d[id].num[1]=d[id].sum[0]=d[id].sum[1]=0;
d[id].laz[0]=d[id].laz[1]=1;
if(l==r){
d[id].num[l&1]++;
d[id].sum[l&1]+=l;
return;
}
int mid=(l+r)>>1;
build(l,mid,id<<1);
build(mid+1,r,id<<1|1);
pushup(id);
return;
}
void update(int l,int r,int id,int op){
pushdown(id);
if(d[id].l==l&&d[id].r==r){
d[id].num[op]=d[id].sum[op]=0;
d[id].laz[op]=0;
return;
}
if(r<=d[ls].r) update(l,r,ls,op);
else if(l>d[ls].r) update(l,r,rs,op);
else{
update(l,d[ls].r,ls,op);
update(d[rs].l,r,rs,op);
}
pushup(id);
return;
}
LL res[2][2];
void ask(int l,int r,int id){
pushdown(id);
if(d[id].l==l&&d[id].r==r){
res[0][0]+=d[id].num[0];
res[1][0]+=d[id].num[1];
res[0][1]+=d[id].sum[0];
res[1][1]+=d[id].sum[1];
return;
}
if(r<=d[ls].r) ask(l,r,ls);
else if(l>d[ls].r) ask(l,r,rs);
else{
ask(l,d[ls].r,ls);
ask(d[rs].l,r,rs);
}
return;
}
void MAIN(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d%d",&a[i].l,&a[i].r);
}
sort(a+1,a+1+n,cmp);
cnt=0;
int cur,L,R;
for(int i=1,j=1;i<=m;++i){
while(j<=n&&a[j].l==i){
ed[a[j].r&1].insert(a[j].r);
++j;
}
while(!ed[0].empty()){
it=ed[0].begin();
if((*it)<i) ed[0].erase(it);
else break;
}
while(!ed[1].empty()){
it=ed[1].begin();
if((*it)<i) ed[1].erase(it);
else break;
}
R=m;L=R+1;
if((!ed[1].empty())||(!ed[0].empty())) L=i;
if(j<=n) L=min(L,a[j].l);
cur=i&1;
if(ed[cur^1].empty()){
q[++cnt]=(Query){i,cur,L,R};
}
else{
it=ed[cur^1].begin();
q[++cnt]=(Query){i,cur,L,(*it)};
}
if(!ed[cur^1].empty()){
continue;
}
if(ed[cur].empty()){
q[++cnt]=(Query){i,cur^1,L,R};
}
else{
it=ed[cur].end();
--it;
q[++cnt]=(Query){i,cur^1,max(L,(*it)+1),R};
}
}
build(1,m,1);
LL ans=0;
for(int i=cnt,j=n;i>=1;--i){
while(j>=1&&a[j].l>q[i].st){
cur=a[j].l&1;
if((a[j].r-a[j].l)&1){
if(a[j].r+1<=m) update(a[j].r+1,m,1,cur);
update(a[j].l,m,1,cur^1);
}
else{
update(a[j].l,a[j].r,1,cur^1);
}
--j;
}
res[0][0]=res[0][1]=res[1][0]=res[1][1]=0;
if(q[i].l<=q[i].r){
ask(q[i].l,q[i].r,1);
ans+=res[q[i].op][1];
ans-=(LL)(q[i].st-1)*res[q[i].op][0];
}
}
printf("%lld\n",ans);
return;
}
int main(){
int ttt=1;
while(ttt--) MAIN();
return 0;
}