[题解]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;
}
浙公网安备 33010602011771号