• [ACNOI2022]总差一步


    《咒骂》

    我也很想过,要写些《闲话》类的东西,然而考虑到其中所必定会带有的负能量,以及预想到校长和卷爷——或许还有狗狗——在评论区的辛辣的嘲讽,终究作罢。

    说到底我并没有写《闲话》的资格。卷爷成绩好,所以他做什么都是合情合理的。我不是那样的。我什么权利也没有。我什么也不是。

    我的心底只有寒冷、黑暗和死亡。我的生活只值得咒骂而不值得闲谈。我只能把它命名为《咒骂》而再没有别的内容。

    可此后这念头就深深扎根在心底。像一座死火山,哪怕它是 “死” 的,它的内部也仍然是滚烫的岩浆。因此我借博客前的一点空间,稍微写点什么吧。

    最近发生了很多不可思议的事,而且接二连三:先是角膜塑形镜意外遗失,接着牙套遗失,然后框架眼镜的眼镜腿断掉,现在考试连续垫底。

    这似乎是某种预兆。某种我不愿去承认,但已经心知肚明的预兆。

    但,或许,这也是好事。它至少让我的心理负担没那么重。

    我已经对自己的弱小熟视无睹了。对自己的无能见怪不怪了。对自己的愚蠢毫不意外了。


    题目

    题目背景
    因为 O U Y E \sf OUYE OUYE 过分内卷,像我一样的普通人已经 没有 生存 空间 了。

    题目描述
    考虑 2 k 2^k 2k 个叶子的线段树,每个节点的值是子节点的较大值。

    叶子值是 [ 1 , 2 k ] [1,2^k] [1,2k] 给定排列。现在 q q q 次询问 x , y x,y x,y,问 x x x 值最多能在多少个节点上出现,如果交换至多 y y y 次叶子的值。

    强制在线,且空间限制 16 M i B 16\rm MiB 16MiB

    数据范围与提示
    k ⩽ 19 k\leqslant 19 k19 q ⩽ 2 × 1 0 5 q\leqslant 2\times 10^5 q2×105

    思路

    y ≠ 0 y\ne 0 y=0,则只需判断某层上,是否有节点拥有至多 y y y 个大于 x x x 的值。

    y = 0 y=0 y=0 时线段树没有变动,可以直接数出答案。故下略。

    扫描线

    看到大于 x x x,考虑从大到小依次处理 x x x

    每次将一个新元素插入,这将影响到 k k k 层内各一个节点。然后我们要维护每层的 min ⁡ c n t \min cnt mincnt 。用数据结构维护,似乎是 O ( k 2 2 k ) \mathcal O(k^22^k) O(k22k) 的复杂度。

    其实每层记录 min ⁡ \min min 的出现次数,发现 min ⁡ \min min 变化后暴力重新计算即可。因为有 L L L 个节点的层中, min ⁡ \min min 不会超过 2 k L 2^k\over L L2k,而每次增加需要 O ( L ) \mathcal O(L) O(L) 重新计算,因此 k k k 层的总复杂度 O ( k 2 k ) \mathcal O(k2^k) O(k2k)

    这样我们就得到每个 x x x 想要在 t t t 个节点上出现时, y y y 至少是多少。如果存储下来,就可以在线处理所有询问了。复杂度 O ( k 2 k + q log ⁡ k ) \mathcal O(k2^k+q\log k) O(k2k+qlogk) 。若在线,空间复杂度 O ( k 2 k ) \mathcal O(k2^k) O(k2k),若离线,空间复杂度 O ( 2 k + q ) \mathcal O(2^k+q) O(2k+q)

    二维偏序

    扫描线 是每个 x x x 去查询可用的线段树节点。

    反过来考虑:每个线段树节点能给 x x x 提供什么。

    显然第 t t t 大的值 v v v 给出了限制:若 x ⩾ v x\geqslant v xv,则 y ⩾ t − 1 y\geqslant t{-}1 yt1 时能获得该区间的答案。

    注意到每层只有 O ( 2 k ) \mathcal O(2^k) O(2k) 个这样的贡献,直接用数组暴力扫描线记下答案即可。

    求出的这个数组和 扫描线 中得到的结果是相同的。

    转换维度

    注意到 半平面 中,给出的限制 y ⩾ t − 1 y\geqslant t{-}1 yt1 只有 L L L 种,其中 L L L 是单个节点的长度。

    因此我们记录 f ( t ) f(t) f(t) 为,在 y ⩾ t − 1 y\geqslant t{-}1 yt1 时, x ⩾ f ( t ) x\geqslant f(t) xf(t) 可达到该层。

    由于每层的 f f f 的长度和是 O ( 2 k ) \mathcal O(2^k) O(2k),空间复杂度就是 O ( 2 k ) \mathcal O(2^k) O(2k) 的。

    询问仍然可以二分,时间复杂度 O ( k 2 k + q log ⁡ k ) \mathcal O(k2^k+q\log k) O(k2k+qlogk),空间复杂度 O ( 2 k ) \mathcal O(2^k) O(2k)

    别出心裁

    怎么强制在线?利用上一个答案。

    然而答案只有 k k k 种,因此将这 O ( q k ) \mathcal O(qk) O(qk) 个询问离线下来,我们也得到可通过的做法。

    代码

    #include 
    #include  // Almighty XJX yyds!!
    #include  // oracle: ZXY yydBUS!!!
    #include  // rainybunny root of the evil.
    #include 
    using llong = long long;
    # define rep(i,a,b) for(int i=(a); i<=(b); ++i)
    # define drep(i,a,b) for(int i=(a); i>=(b); --i)
    # define rep0(i,a,b) for(int i=(a); i!=(b); ++i)
    inline int readint(){
        int a = 0, c = getchar(), f = 1;
        for(; !isdigit(c); c=getchar()) if(c == '-') f = -f;
        for(; isdigit(c); c=getchar()) a = a*10+(c^48);
        return a*f;
    }
    
    const int MAXK = 19;
    int a[1<<MAXK]; int* tag[MAXK];
    int ori[1<<MAXK]; /** for y = 0 */
    
    const int INF = 0x3fffFFFF;
    int tmp[1<<MAXK];
    int main(){
        int n = readint(), k = readint(), typ = readint();
        rep0(i,0,n) a[i] = readint()-1;
        rep0(j,0,k){ // merge for each layer
            tag[j] = new int[2<<j];
            std::fill_n(tag[j],2<<j,INF);
            int* l = a; int* r = a+(2<<j);
            for(; l!=a+n; r+=(2<<j)){
                int* const mid = l+(1<<j);
                ori[std::min(*l,*mid)] = j; // lose here
                std::merge(l,mid,mid,r,tmp,std::greater<int>());
                memcpy(l,tmp,(2<<j)<<2); // copy back
                for(int* i=tag[j]; l!=r; ++l,++i)
                    *i = std::min(*i,*l); // corresponding
            }
        }
        ori[n-1] = k; // the final winner
        for(int q=readint(),x,y,ans=0; q; --q){
            x = readint(), y = readint();
            if(typ) x ^= ans, y ^= ans;
            if(!y){ printf("%d\n",ans=ori[x-1]); continue; }
            int l = 31-__builtin_clz(y); /** smaller than @a y */
            int r = 31-__builtin_clz(x--); /** too big to replace */
            if(l > r){ printf("%d\n",ans=r); continue; }
            while(l != r){
                const int mid = (l+r+1)>>1;
                if(tag[mid-1][y] <= x) // acceptable
                    l = mid; else r = mid-1;
            }
            printf("%d\n",ans=r);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
  • 相关阅读:
    C++常用23种设计模式总结(三)------装饰模式
    登录远程SQLServer
    测试工具介绍||Postman的简单使用
    MAC M芯片 Anaconda安装
    SELinux零知识学习十五、SELinux策略语言之客体类别和许可(9)
    简单选择排序(c语言代码实现)
    JDBC 1
    【iOS ARKit】PhysicsBodyComponent
    SpringBoot服务集成ELK
    竞赛 题目:基于深度学习卷积神经网络的花卉识别 - 深度学习 机器视觉
  • 原文地址:https://blog.csdn.net/qq_42101694/article/details/126002173