LGP9478 [NOI 2023] 方格染色 学习笔记

LGP9478 [NOI 2023] 方格染色 学习笔记

Luogu Link

前言

2023:

\(\texttt{NOI}\) 为什么会出这么简单的题目。不过我省队都进不了,管这些干什么。——\(\text{Purslane}\)

2024:

没想到 \(\texttt{NOI2024 d1t1}\) 更加弱智,打 \(\texttt{OI}\) 的这辈子有了。

2025:

(你知道这年的签到是个什么东西)
(另外 \(\text{Purslane}\) 金了)

笑点解析:

  1. 这题在洛谷上被降蓝了。
  2. 截止 \(\texttt{20250724}\)\(\text{OrinLoong}\) 做完了三年的国赛签到,然而他连七级钩都没有。
  3. 上面的截止日期本来是二十三号,但因为这题调起来太史导致二十三号没调完。

题意简述

\(n\times m\) 的棋盘格。记第 \(i\) 列,第 \(j\) 行的方格坐标记为 \((i,j)\)

三种操作。染一条横线、染一条竖线、染一条斜率为 \(1\) 的斜线。最多染 \(5\) 次斜线。

问最终有多少个格子被染。

\(n,m\le 10^9\)\(q\le 10^5\)

做法解析

没有斜线时显然是矩形面积并模板,不会的出门左转这里。不过这两题的代码还是有一些区别,因为这题给的都是格子的坐标。为了简单处理这一点,我们给所有直线(即矩形)那个较大的 \(x_i\)\(y_i\)\(1\)

如果坐标值域没到 \(10^9\) ,斜线可以暴力拆成一个一个 \(1\times 1\) 方格参与矩形面积并计算(这足够你获得 \(\text{95pts}\))。但坐标值域到了 \(10^9\) 怎么办呢?考虑先把斜线面积全算上再去重。为了防止一个斜线和多条直线相交于同一点而被去重多次,可以开个map来防止多次去重。

代码实现

代码里那个sort(Xs+1,Xs+scnt+1)是因为这里离散化前的x坐标数量确实就等于scnt

如果一遍没写对调起来会挺折磨。给这题降蓝的多少有点 \(\texttt{starbeat}\)

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxQ=1e5+5;
int Tpn,N,M,Q,Opt,X1,Y1,X2,Y2,scnt;
int Xs[MaxQ<<1],xcnt;
struct oper{int o,lx,ly,rx,ry;}P[MaxQ];
struct anob{int lx,rx,y,w;}S[MaxQ<<1];
bool cmpy(anob a,anob b){return a.y<b.y;}
struct SegTree{
    int cov[MaxQ<<3],flen[MaxQ<<3];
    int ls(int u){return u<<1;}
    int rs(int u){return (u<<1)|1;}
    void pushup(int u,int cl,int cr){
        if(cov[u]){flen[u]=Xs[cr+1]-Xs[cl];return;}
        flen[u]=(cl==cr?0:flen[ls(u)]+flen[rs(u)]);
    }
    void update(int u,int cl,int cr,int dl,int dr,int x){
        if(dl<=cl&&cr<=dr){cov[u]+=x,pushup(u,cl,cr);return;}
        int cmid=(cl+cr)>>1;
        if(dl<=cmid)update(ls(u),cl,cmid,dl,dr,x);
        if(dr>cmid)update(rs(u),cmid+1,cr,dl,dr,x);
        pushup(u,cl,cr);
    }
}SgT;
lolo ans;int tcnt,flg[6];
struct bnob{int lx,rx,ly;}T[6];
void tcomb(){
    for(int i=1;i<=tcnt;i++)flg[i]=1;
    for(int i=1;i<=tcnt;i++){
        if(!flg[i])continue;
        for(int j=i+1;j<=tcnt;j++){
            if(!flg[j])continue;
            if(T[i].ly-T[i].lx!=T[j].ly-T[j].lx)continue;
            if(T[i].rx<=T[j].lx||T[j].rx<=T[i].lx)continue;
            minner(T[i].lx,T[j].lx),maxxer(T[i].rx,T[j].rx),minner(T[i].ly,T[j].ly),flg[j]=0;
        }
    }
}
int main(){
    readi(Tpn);readis(N,M,Q);
    for(int i=1;i<=Q;i++){
        readis(Opt,X1,Y1,X2,Y2),X2++,Y2++;
        P[i]={Opt,X1,Y1,X2,Y2};
        Xs[(i<<1)-1]=X1,Xs[i<<1]=X2;
        if(Opt==3)T[++tcnt]={X1,X2,Y1};
        else S[++scnt]={X1,X2,Y1,1},S[++scnt]={X1,X2,Y2,-1};
    }
    sort(S+1,S+scnt+1,cmpy);
    sort(Xs+1,Xs+(Q<<1)+1),xcnt=unique(Xs+1,Xs+(Q<<1)+1)-(Xs+1);
    for(int i=1;i<=scnt;i++)S[i].lx=lwberi(Xs,xcnt,S[i].lx),S[i].rx=lwberi(Xs,xcnt,S[i].rx)-1;
    for(int i=1;i<scnt;i++){
        auto [lx,rx,y,w]=S[i];
        SgT.update(1,1,xcnt-1,lx,rx,w);
        ans+=1ll*SgT.flen[1]*(S[i+1].y-S[i].y);
    }
    tcomb();map<pii,bool> mp;
    for(int i=1;i<=tcnt;i++)if(flg[i])ans+=T[i].rx-T[i].lx;
    for(int j=1;j<=tcnt;j++){
        if(!flg[j])continue;
        auto [jlx,jrx,jly]=T[j];
        int jry=jly+(jrx-jlx);
        for(int i=1;i<=Q;i++){
            auto &[co,clx,cly,crx,cry]=P[i];
            if(co==1){
                if(cry<=jly||jry<=cly)continue;
                int jtx=jlx+(cly-jly);if(jtx>=crx||jtx<clx)continue;
                pii cp={jtx,cly};if(!mp[cp])mp[cp]=1,ans--;
            }
            if(co==2){
                if(crx<=jlx||jrx<=clx)continue;
                int jty=jly+(clx-jlx);if(jty>=cry||jty<cly)continue;
                pii cp={clx,jty};if(!mp[cp])mp[cp]=1,ans--;
            }
        }
    }
    writil(ans);
    return 0;
}
posted @ 2025-07-24 00:40  矞龙OrinLoong  阅读(15)  评论(0)    收藏  举报