• 洛谷 P5105 不强制在线的动态快速排序


    P5105 不强制在线的动态快速排序

    题目背景

    曦月最近学会了快速排序,但是她很快地想到了,如果要动态地排序,那要怎么办呢?

    题目描述

    为了研究这个问题,曦月提出了一个十分简单的问题

    曦月希望维护一个允许重复的集合(S),支持:

    • 插入([L, R]),也就是插入(L, L + 1 ... , R),这(R - L + 1)个数
    • 询问(Sort(S))

    (Sort(S))的定义为:

    我们将集合(S)中的元素从小到大按照快速排序排好序,记为(a_1, a_2 ... a_n)

    那么,(Sort(S) = igoplus limits_{i = 2}^n (a_i^2 - a_{i - 1}^2)),其中(igoplus)表示异或和

    关于异或的定义,请咨询度娘

    输入输出格式

    输入格式:

    第一行,一个数(q)

    (q)行,或者是(1;l;r),表示插入([l, r]),或者是(2),表示一次询问

    输出格式:

    对于每个询问,一行一个答案

    说明

    对于(30)分的数据,(q leqslant 100)

    对于(50)分的数据,(q leqslant 5 * 10^4)

    对于另外的(20)分的数据,满足(L=R)

    对于(100)分的数据,(q leqslant 3 * 10^5)(1 leqslant L leqslant R leqslant 10^9)


    先考虑单独插入一个区间([l,r])

    然后发现贡献是(igoplus_{i=l}^r 2i+1)

    把每个贡献右移一位,可以用发现是求(igoplus_{i=l}^r i),然后特判一下最后一位的奇偶。

    异或前缀和有个结论

    int cal(int n)
    {
        if(n%4==0) return n;
        if(n%4==1) return 1;
        if(n%4==2) return n+1;
        if(n%4==3) return 0;
    }
    

    多组显然可以平衡树,但是写起来很麻烦

    于是可以用线段树直接维护区间插入,对每个区间维护最左和最右位置,然后直接合并左右儿子时计算一下贡献就可以了。


    Code:

    #include <cstdio>
    #define int long long
    const int N=3e5+10;
    int cal(int n)
    {
        if(n%4==0) return n;
        if(n%4==1) return 1;
        if(n%4==2) return n+1;
        if(n%4==3) return 0;
    }
    #define ls ch[now][0]
    #define rs ch[now][1]
    int sum[N*20],ch[N*20][2],lp[N*20],rp[N*20],is[N*20],tot,root;
    void change(int &now,int L,int R,int l,int r)
    {
        if(is[now]) return;
        if(!now) now=++tot;
        if(L==l&&R==r)
        {
            is[now]=1;
            if(l!=r) sum[now]=((cal(r-1)^cal(l-1))<<1)|(r-l&1);
            lp[now]=l;
            rp[now]=r;
            return;
        }
        int Mid=L+R>>1;
        if(r<=Mid) change(ls,L,Mid,l,r);
        else if(l>Mid) change(rs,Mid+1,R,l,r);
        else change(ls,L,Mid,l,Mid),change(rs,Mid+1,R,Mid+1,r);
        lp[now]=lp[ls];
        if(!lp[now]) lp[now]=lp[rs];
        rp[now]=rp[rs];
        if(!rp[now]) rp[now]=rp[ls];
        sum[now]=sum[ls]^sum[rs];
        if(rp[ls]&&lp[rs])
            sum[now]^=(lp[rs]+rp[ls])*(lp[rs]-rp[ls]);
    }
    const int M=1e9;
    signed main()
    {
        int n;scanf("%lld",&n);
        for(int op,l,r,i=1;i<=n;i++)
        {
            scanf("%lld",&op);
            if(op==2)
                printf("%lld
    ",sum[root]);
            else
            {
                scanf("%lld%lld",&l,&r);
                change(root,1,M,l,r);
            }
        }
        return 0;
    }
    

    2018.12.16

  • 相关阅读:
    memcache清理缓存
    JqGrid常见使用方法
    SQLyog 最新版本12.5-64bit 完美破解,亲测可用!
    Navicat Premium 最新版本12.1.16-64bit 完美破解,亲测可用!
    【JAVA基础】一:聊聊笔试常见到的 “==、equal” 比较是否相等的内在差别
    scrapy 爬虫返回json格式内容unicode编码转换为中文的问题解决
    Python3的桌面程序开发利器:Eric6的环境搭建、使用
    通过Redis、Memcache的 incr 原子操作防刷机制的使用差别
    从零开始搭建一个从Win7环境备份至CentOS7的SVN双机备份环境
    通过Quartz 配置定时调度任务:使用cron表达式配置时间点
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10127654.html
Copyright © 2020-2023  润新知