1 条题解

  • 0
    @ 2025-8-24 23:12:28

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar myee
    与其诺诺以顺,不若谔谔以昌 | AFO

    搬运于2025-08-24 23:12:28,当前版本为作者最后更新于2025-04-08 18:29:57,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    前言

    出题人题解。

    如你所见这是在你清食堂吃饭的真实经历……

    原本是命题会上发现缺一个模拟,于是我就掏出了一个这个,大家一致通过后就选上了。

    应该算是近几年 THUPC 最简单的几道模拟之一了?

    本题的 CF ver. 是一个弱化版本,可以进一步优化到不带 log\log

    思路

    观察到性质:当座位同样可选时,优先级是确定的。我们不妨先对此进行排序。这部分使用 BFS 或者数学方法 d(x,y)=x+y+2[xmod3=ymod3=2]d(x,y)=x+y+2[x\bmod3=y\bmod3=2] 容易做到线性。

    那么我们的目标每次就是要找到一个编号尽可能小的符合某种要求的可选座位,或者翻转某个座位的状态。

    观察到找到可选座位的过程只可能涉及 O(q)O(\sqrt q) 坐标范围内的桌子(是一个 30003000 左右的上界),我们不妨把坐标范围不在指定范围内的翻转操作单独用一个哈希表来处理。

    这样为了维护第一种操作,我们只用考虑 O(q)O(q) 级别的信息了。

    注意到,“找到编号尽可能小”本身是一个常用维护的结构。而这里我们每次翻转一个座位的状态时,对应的四个格子的可行性都可能发生改变,于是有相应的插入或者删除操作。

    也即,我们需要用可删堆维护每种忍受度的可行编号集合,具体可以使用 set 或者两个 priority_queue 来快速实现。

    总复杂度 O(nlogn)O(n\log n)

    Code

    为了写的尽可能简单一点,std 没有加一些优化。如果加了的话应该能快一倍?

    最终 std 不到 2kb。

    // キミは泣いた後 笑えるはずだから って言ったんだ
    // 仆らの旅 忘れたりしないよ
    // 失くさないよう魔法かけて さよならを伝えない
    // 歩き出すよ またいつか
    
    #include <bits/stdc++.h>
    
    using uint = unsigned;
    using bol = bool;
    
    const uint W=10001;
    const uint T=3031;
    const uint R=2000000;
    
    bol G[T*T];
    uint Id[T*T],Ord[R+5];
    
    uint Nxt(uint p,uint o)
    {
        uint x=p/T,y=p%T;
        if(o&1)y=y/3*3+3-y%3;
        if(o&2)x=x/3*3+3-x%3;
        return x*T+y;
    }
    
    std::set<uint>P[3],Q;
    
    bol flip(uint x,uint y)
    {
        if(x>=T||y>=T)
        {
            if(Q.count(x*W+y))return Q.erase(x*W+y),0;
            return Q.insert(x*W+y),1;
        }
        uint p[4]={0,0,0,0};for(uint i=0;i<4;i++)p[i]=Nxt(x*T+y,i);
        if(G[p[0]])
        {
            G[p[0]]=0;
            for(uint o=0;o<4;o++)if(~Id[p[o]])
            {
                if(!G[p[o]]&&!o)P[2].erase(Id[p[o]]);
                if(!G[p[o]]||!G[p[o^1]]||!G[p[o^2]])P[1].erase(Id[p[o]]);
                P[0].erase(Id[p[o]]);
            }
            return 1;
        }
        else
        {
            G[p[0]]=1;
            for(uint o=0;o<4;o++)if(~Id[p[o]])
            {
                if(G[p[o]])
                {
                    if(!o)P[2].insert(Id[p[o]]);
                    if(G[p[o^1]]&&G[p[o^2]])
                    {
                        if(o!=3)P[1].insert(Id[p[o]]);
                        if(G[p[o^3]])P[0].insert(Id[p[o]]);
                    }
                }
            }
            return 0;
        }
    }
    
    int main()
    {
    #ifdef MYEE
        freopen("QAQ.in","r",stdin);
        freopen("QAQ.out","w",stdout);
    #endif
        G[0]=true;
        for(auto&s:Id)s=-1;
        for(uint tp=0,c=1;tp<R;)
        {
            static uint Now[50005],Next[50005];
            uint t=0;
            for(uint j=0;j<c;j++)
            {
                uint p=Now[j];
                if(p%T&&!G[p-1])G[p-1]=true,Next[t++]=p-1;
                if(p/T&&!G[p-T])G[p-T]=true,Next[t++]=p-T;
                if(p%T+1<T&&!G[p+1])G[p+1]=true,Next[t++]=p+1;
                if(p/T+1<T&&!G[p+T])G[p+T]=true,Next[t++]=p+T;
            }
            std::sort(Next,Next+t),c=0;
            for(uint j=0;j<t;j++)if(Next[j]/T%3&&Next[j]%T%3){if(tp<R)Ord[Id[Next[j]]=tp++]=Next[j];}else Now[c++]=Next[j];
        }
        for(auto&s:G)s=1;
        for(uint i=0;i<R;i++)P[0].insert(i);
        P[1]=P[2]=P[0];
        uint q;scanf("%u",&q);
        while(q--)
        {
            uint t;scanf("%u",&t);
            if(t==1)
            {
                scanf("%u",&t);t=Ord[*P[t].begin()];
                uint x=t/T,y=t%T;printf("%u %u\n",x,y),flip(x,y);
            }
            else
            {
                uint x,y;scanf("%u%u",&x,&y);puts(flip(x,y)?"in":"out");
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    11924
    时间
    3000ms
    内存
    1024MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者