Loading

CF799F Beautiful fountains rows

这个正解比乱搞逊多了

先考虑只枚举 \(a\)

\((x,y)\) 表示 \(x\)\(y\) 都有喷泉的花园且如果在 \([a,x]\) 段上有非零偶数个喷泉,那么对于 \(a\) 来说 \(x\) 是禁止的。

然后考虑将所有花园分为两类:

  1. \(x<a\le y\)

  2. \(a\le x\le y\)

考虑第一类花园中的哪些位置是禁止的:

\(\mathbb R\) 为第一类花园的右端点集合,这些花园禁止位置 \(a+1,a+3,\cdots,x\)。且若 \(\mathbb R\) 中存在一个 \(t\) 满足 \(t-a+1\) 是偶数,那么位置 \(t,t+1,t+2,\cdots ,m\) 也将被禁止。显然只需要知道最小的 \(t\) 满足 \(t-a+1\) 是偶数就行了。

然后考虑第二类花园中的哪些位置是禁止的:

\(x+1,x+3,\cdots\)。且若 \(y-x+1\) 为偶数,则 \(y,y+1,y+2,\cdots\) 这些位置也都是禁止的。

可以发现哪些位置被禁止与 \(a\) 无关,因此可以预处理一个数组来求出有哪些 \(b\) 是禁止的。

然后考虑直接拿线段树维护上面那一堆东西,具体可以看代码..

时间复杂度 \(\mathcal O(n\log (n+m))\),比乱搞慢好几倍而且难写。

#include<bits/stdc++.h>
#define R(i,a,b) for(int i=(a),i##E=(b);i<=i##E;i++)
#define L(i,a,b) for(int i=(b),i##E=(a);i>=i##E;i--)
using namespace std;
typedef long long ll;
ll ans;
int n,m;
int a[222222],l[222222],r[222222];
struct sgt
{
	struct node
	{
		int mn,cnt;
		ll val;
		inline node (int M=0,int C=0,ll V=0):mn(M),cnt(C),val(V) {}
		inline node operator +(const node &A)const
		{
			if(mn<A.mn) return *this;
			if(mn>A.mn) return A;
			return node(mn,cnt+A.cnt,val+A.val);
		}
	}t[888888];
	int lz[888888];
	inline void push_add(int x,int k)
	{
		t[x].mn+=k,lz[x]+=k;
	}
	inline void push_down(int x)
	{
		push_add(x<<1,lz[x]),push_add(x<<1|1,lz[x]);
		lz[x]=0;
	}
	void build(int opt,int l,int r,int x)
	{
		lz[x]=0;
		if(l==r) 
		{
			t[x].mn=0;
			if((l&1)==opt) t[x].cnt=1,t[x].val=l;
			else t[x].cnt=t[x].val=0;
			return;
		}
		int mid=(l+r)>>1;
		build(opt,l,mid,x<<1);
		build(opt,mid+1,r,x<<1|1);
		t[x]=t[x<<1]+t[x<<1|1];
	}
	void modify(int L,int R,int l,int r,int x,int k)
	{
		if(L<=l&&r<=R) return push_add(x,k);
		push_down(x);
		int mid=(l+r)>>1;
		if(L<=mid) modify(L,R,l,mid,x<<1,k);
		if(mid<R) modify(L,R,mid+1,r,x<<1|1,k);
		t[x]=t[x<<1]+t[x<<1|1];		
	}
	node query(int L,int R,int l,int r,int x)
	{
		if(L<=l&&r<=R) return t[x];
		push_down(x);
		int mid=(l+r)>>1;
		if(R<=mid) return query(L,R,l,mid,x<<1);
		if(L>mid) return query(L,R,mid+1,r,x<<1|1);
		return query(L,R,l,mid,x<<1)+query(L,R,mid+1,r,x<<1|1);
	}	
}st;
inline void solve(int fl,int fr)
{
	st.build(fr,1,m,1);
	vector<tuple<int,int,int> >op[222222];
	R(i,1,n)
	{
		//a<x<y
		if((fr-l[i])&1)//x+1,x+3....
		{
			op[1].emplace_back(l[i],r[i],1);
			op[l[i]].emplace_back(l[i],r[i],-1);
		}
		if((r[i]-l[i])&1) //y,y+1...m
		{
			op[1].emplace_back(r[i]+1,m,1);
			op[l[i]].emplace_back(r[i]+1,m,-1);
		}
		//x<a<y
		if((r[i]-fl)&1)//b>y
		{
			op[l[i]].emplace_back(r[i]+1,m,1);
			op[r[i]+1].emplace_back(r[i]+1,m,-1);
		}
		if((fr-fl)&1)//a+1,a+3,max{R}
		{
			op[l[i]].emplace_back(l[i],r[i],1);
			op[r[i]+1].emplace_back(l[i],r[i],-1);
		}
	}
	//st.print(1,m,1),printf("-----------------\n");
	R(i,1,m)
	{
		//for(auto [l,r,k]:op[i]) printf("l:%d r:%d k:%d\n",l,r,k);
		for(auto [l,r,k]:op[i]) if(l<=r)
			st.modify(l,r,1,m,1,k);//st.print(1,m,1),printf("-----------------\n");
		if(i%2==fl) 
		{
			auto ret=st.query(i,m,1,m,1);
			if(!ret.mn) ans+=ret.val-1ll*ret.cnt*(i-1);
		}
	}
}	
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n>>m;
	R(i,1,n) cin>>l[i]>>r[i],++a[l[i]],--a[r[i]+1];
	R(i,1,m) a[i]+=a[i-1];
	solve(0,0),solve(0,1),solve(1,0),solve(1,1);
	for(int i=1,j=1;i<=m;i=j+1,++j) if(!a[i]) 
	{
		for(;j+1<=m&&!a[j+1];++j);
		int t=j-i+1;
		R(k,1,t) ans-=1ll*k*(t-k+1);
	}
	cout<<ans<<endl;

}
posted @ 2022-03-19 00:18  yoisaki_hizeci  阅读(18)  评论(0)    收藏  举报