[题解]P9478 [NOI2023] 方格染色

P9478 [NOI2023] 方格染色

考虑特殊问题一般化。若只有行和列的操作,可以直接扫描线,计算矩形面积并。

斜方向的操作最多进行 \(5\) 次,所以每个操作可以拆成 \(O(n)\) 个小正方形参与面积并。

这样就能拿 \(95\) 了。

瓶颈在于斜方向有一个 \(O(n)\),所以考虑不拆成小正方形,而是先计算没有斜线的答案,再枚举每一条斜线。

对于枚举的斜线,我们可以 \(O(q)\) 地遍历行和列的操作,并求出于它重合的位置数量(注意使用 set 去重)。对答案的贡献即为斜线长度、再减去重合位置的数量。

时间复杂度 \(O(q\log q)\)


实现细节上,需要注意两斜线若存在公共点,需要将它们合并成一条,否则会重复统计答案。

我采取的方法是根据 \(y-x\) 相同的斜线共线,将 \(y-x=p\) 相同的斜线放在一起进行合并。

然后枚举所有斜线。对于 \((p,x_l,x_r)\) 这条斜线:

  • 其与横向线段 \((y,l,r)\) 有交点,当且仅当存在 \(x\in[l,r]\),使得 \(y-x=p\),且 \(x\in[x_l,x_r]\),即:

    \[y-p\in[\max(x_l,l),\min(x_r,r)] \]

  • 其与纵向线段 \((x,l,r)\) 有交点,当且仅当存在 \(y\in[l,r]\),使得 \(y-x=p\),且 \(y-p\in[x_l,x_r]\),即:

    \[x+p\in[\max(l,x_l+p),\min(r,x_r+p)] \]

点击查看代码
#include<bits/stdc++.h>
#define eb emplace_back
#define PII pair<int,int>
#define int long long
#define lc (x<<1)
#define rc (x<<1|1)
using namespace std;
const int N=1e5+5;
inline bool in(int x,int l,int r){return x>=l&&x<=r;}
int c,n,m,q,idx,tn,X[N<<1],ans;
struct SEG{
	int lp[N<<4],rp[N<<4],sum[N<<4],len[N<<4];
	void build(int x,int l,int r){
		lp[x]=l,rp[x]=r;
		if(l==r) return;
		int mid=(l+r)>>1;
		build(lc,l,mid),build(rc,mid+1,r);
	}
	void pushup(int x){
		if(sum[x]) len[x]=X[rp[x]+1]-X[lp[x]];
		else len[x]=(lp[x]!=rp[x])*(len[lc]+len[rc]);
	}
	void chr(int x,int a,int b,int v){
		if(X[rp[x]+1]<=a||b<=X[lp[x]]) return;
		if(a<=X[lp[x]]&&X[rp[x]+1]<=b) sum[x]+=v;
		else chr(lc,a,b,v),chr(rc,a,b,v);
		pushup(x);
	}
}seg;
struct Line{
	int l,r,h,o;
	bool operator < (const Line &_) const{return h<_.h;}
}s[N<<1];
struct Hor{int y,l,r;};
struct Ver{int x,l,r;};
map<int,list<PII>> ks;//koishi
set<int> se;//visited
vector<Hor> hs;//horizon
vector<Ver> vs;//vertical
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>c>>n>>m>>q; 
	int op,x,y,xx,yy;
	while(q--){
		cin>>op>>x>>y>>xx>>yy;
		if(op==1){
			hs.eb(Hor{y,x,xx});
			s[++idx]={x-1,xx,y-1,1};
			s[++idx]={x-1,xx,y,-1};
			X[++tn]=x-1,X[++tn]=xx;
		}else if(op==2){
			vs.eb(Ver{x,y,yy});
			s[++idx]={x-1,x,y-1,1};
			s[++idx]={x-1,x,yy,-1};
			X[++tn]=x-1,X[++tn]=x;
		}else{
			ks[y-x].eb(x,xx);
		}
	}
	sort(s+1,s+1+idx);
	sort(X+1,X+1+tn),tn=unique(X+1,X+1+idx)-X-1;
	seg.build(1,1,tn-1);
	//处理横纵 
	for(int i=1;i<idx;i++){
		seg.chr(1,s[i].l,s[i].r,s[i].o);
		ans+=seg.len[1]*(s[i+1].h-s[i].h);
	}
	//处理斜向
	for(auto& koishi:ks){
		int p=koishi.first;
		auto &li=koishi.second;
		li.sort();
		for(auto it=li.begin(),lst=li.end();it!=li.end();){//合并有交的线段
			if(lst!=li.end()&&(*it).first<=(*lst).second){
				(*lst).second=max((*lst).second,(*it).second);
				li.erase(it++);
			}else lst=it++;
		}
		for(PII i:li){
			se.clear();
			for(Hor j:hs){
				if(in(j.y-p,i.first,i.second)&&in(j.y-p,j.l,j.r)){
					se.insert(j.y-p);
				}
			}
			for(Ver j:vs){
				if(in(j.x,i.first,i.second)&&in(j.x+p,j.l,j.r)){
					se.insert(j.x);
				}
			}
			ans+=i.second-i.first+1-se.size();
		}
	}
	cout<<ans<<"\n";
	return 0;
}
posted @ 2025-10-24 14:42  Sinktank  阅读(12)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.