题意

您需要写一种数据结构,来维护一个序列,其中需要提供以下操作(对于各个以往的历史版本):

  1. 在第 pp 个数后插入数 xx 。
  2. 删除第 pp 个数。
  3. 翻转区间 [l,r][l,r],例如原序列是 {5,4,3,2,1}{5,4,3,2,1},翻转区间 [2,4][2,4] 后,结果是 {5,2,3,4,1}{5,2,3,4,1}。
  4. 查询区间 [l,r][l,r] 中所有数的和。

和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本(操作 44 即保持原版本无变化),新版本即编号为此次操作的序号。

本题强制在线。

分析

函数式Treap实现。

时空复杂度\(O(n \log n)\)

代码

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cstring>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>T read(T&x)
{
    return x=read<T>();
}
typedef long long ll;

co int N=2e5+7;
int tot;
int root[N];
int can[N],cantop;
namespace T
{
    using std::swap;

    int ch[N<<6][2],siz[N<<6];
    int pri[N<<6],val[N<<6];
    ll sum[N<<6];
    bool rev[N<<6];

    int newnode(int v=0)
    {
        int x=cantop?can[cantop--]:++tot;
        ch[x][0]=ch[x][1]=0,siz[x]=1;
        pri[x]=rand()<<15|rand(),val[x]=sum[x]=v;
        rev[x]=0;
        return x;
    }

    int clone(int y)
    {
        int x=cantop?can[cantop--]:++tot;
        ch[x][0]=ch[y][0],ch[x][1]=ch[y][1],siz[x]=siz[y];
        pri[x]=pri[y],val[x]=val[y],sum[x]=sum[y];
        rev[x]=rev[y];
        return x;
    }

    void pushup(int x)
    {
        siz[x]=siz[ch[x][0]]+1+siz[ch[x][1]];
        sum[x]=sum[ch[x][0]]+val[x]+sum[ch[x][1]];
    }

    void pushdown(int x)
    {
        if(rev[x])
        {
            swap(ch[x][0],ch[x][1]);
            if(ch[x][0])
            {
                ch[x][0]=clone(ch[x][0]);
                rev[ch[x][0]]^=1;
            }
            if(ch[x][1])
            {
                ch[x][1]=clone(ch[x][1]);
                rev[ch[x][1]]^=1;
            }
            rev[x]=0;
        }
    }

    void split(int x,int k,int&l,int&r)
    {
        if(!x)
        {
            l=r=0;
            return;
        }
        pushdown(x);
        if(k<=siz[ch[x][0]])
        {
            r=clone(x);
            split(ch[r][0],k,l,ch[r][0]);
            pushup(r);
        }
        else
        {
            l=clone(x);
            split(ch[l][1],k-siz[ch[x][0]]-1,ch[l][1],r);
            pushup(l);
        }
    }

    int merge(int x,int y)
    {
        if(!x||!y)
            return x+y;
        if(pri[x]<pri[y])
        {
            pushdown(y);
            ch[y][0]=merge(x,ch[y][0]);
            pushup(y);
            return y;
        }
        else
        {
            pushdown(x);
            ch[x][1]=merge(ch[x][1],y);
            pushup(x);
            return x;
        }
    }

    void insert(int&rt,int k,int v)
    {
        int x,y;
        split(rt,k,x,y);
        rt=merge(x,merge(newnode(v),y));
    }

    void erase(int&rt,int p)
    {
        int x,y,z;
        split(rt,p,x,z);
        split(x,p-1,x,y);
        can[++cantop]=y;
        rt=merge(x,z);
    }

    void reverse(int&rt,int l,int r)
    {
        int x,y,z;
        split(rt,r,x,z);
        split(x,l-1,x,y);
        rev[y]^=1;
        rt=merge(x,merge(y,z));
    }

    ll query(int&rt,int l,int r)
    {
        int x,y,z;
        split(rt,r,x,z);
        split(x,l-1,x,y);
        ll ans=sum[y];
        rt=merge(x,merge(y,z));
        return ans;
    }
}
using namespace T;
using namespace std;

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    int n=read<int>();
    ll lastans=0;
    for(int i=1;i<=n;++i)
    {
        int v,q;
        read(v),read(q);
        root[i]=root[v];
        if(q==1)
        {
            int p,x;
            read(p),read(x);
            p^=lastans,x^=lastans;
            insert(root[i],p,x);
        }
        else if(q==2)
        {
            int p;
            read(p);
            p^=lastans;
            erase(root[i],p);
        }
        else if(q==3)
        {
            int l,r;
            read(l),read(r);
            l^=lastans,r^=lastans;
            reverse(root[i],l,r);
        }
        else
        {
            int l,r;
            read(l),read(r);
            l^=lastans,r^=lastans;
            printf("%lld\n",lastans=query(root[i],l,r));
        }
    }
    return 0;
}

LG5055 【模板】可持久化文艺平衡树的更多相关文章

  1. 【LG5055】可持久化文艺平衡树

    [LG5055]可持久化文艺平衡树 题面 洛谷 题解 终于不可以用\(Trie\)水了... 和普通的\(FHQ\;treap\)差不多 注意一下\(pushdown\).\(split\)要新开节点 ...

  2. P5055 【模板】可持久化文艺平衡树 可持久化fhqtreap

    P5055 [模板]可持久化文艺平衡树 链接 luogu 思路 可持久化fhq-treap套一套就行了,pushdown和split都要可持久化,但merge不用可持久.以前以为很难一直没看,就是个板 ...

  3. 洛谷P5055 可持久化文艺平衡树 (可持久化treap)

    题目链接 文艺平衡树的可持久化版,可以使用treap实现. 作为序列使用的treap相对splay的优点如下: 1.代码短 2.容易实现可持久化 3.边界处理方便(splay常常需要在左右两端加上保护 ...

  4. 【模板】可持久化文艺平衡树-可持久化treap

    题目链接 题意 对于各个以往的历史版本实现以下操作: 在第 p 个数后插入数 x . 删除第 p 个数. 翻转区间 [l,r],例如原序列是 \(\{5,4,3,2,1\}\),翻转区间 [2,4] ...

  5. Luogu5055 【模板】可持久化文艺平衡树(fhq-treap)

    注意下传标记时也需要新建节点.空间开的尽量大. #include<iostream> #include<cstdio> #include<cmath> #inclu ...

  6. 洛谷P5055 【模板】可持久化文艺平衡树(FHQ Treap)

    题面 传送门 题解 日常敲板子.jpg //minamoto #include<bits/stdc++.h> #define R register #define inline __inl ...

  7. luoguP5055 【模板】可持久化文艺平衡树 可持久化非旋转treap

    好题. Code: #include<bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in&quo ...

  8. SLT学习——leafes tree扩展 【文艺平衡树】

    这是一个全新的数据结构 md,别看这篇文章了,这篇已经废了. 百折不饶,再交一次,更新复杂度证明 这里是HYF,蒟蒻一只,最近因某些原因开始学数据结构了,然后就写了这篇题解. 下面给大家介绍一个全新的 ...

  9. 洛谷 P3391 【模板】文艺平衡树

    题目背景 这是一道经典的Splay模板题--文艺平衡树. 题目描述 您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4 ...

随机推荐

  1. HTML5/CSS3实现图片倒影效果

    在线演示 本地下载

  2. 20145120黄玄曦《网络对抗》Web安全基础实践

    20145120黄玄曦<网络对抗>Web安全基础实践 回答问题 (1)SQL注入攻击原理,如何防御 SQL注入原理简单地说大概是,通过构造特殊的SQL命令提交表单,让服务器执行构造的恶意S ...

  3. 一些好用的Linux命令工具

    刚好看到一个系列的博文,讲的就是那些平时很少被人用到但是很实用的命令,选一些觉得自己应该比较常用到的出来写个笔记. 这些命令有些不是系统命令,需要自行下载安装.Debian下安装:sudo apt-g ...

  4. 将CString写入到本地文件中

    void SocketU::WritePacket2File(CString packet_str)//packet_str为待写入的字符串{ CTime time = CTime::GetCurre ...

  5. ()IT 职场经验)一位10年Java工作经验的架构师的经验分享,感觉很受用。

    阿里巴巴技术大牛黄勇的经验分享,感觉很受用. 关于IT 职场经验 1. 把技术当成工具 技术这东西,其实一点都不神秘,它只不过是一个工具,用这个工具可以帮助我们解决实际问题,就这么简单. 我们每天在面 ...

  6. 《大型网站系统与JAVA中间件实践》读书笔记-消息中间件

    消息中间件 1.消息中间件的价值 1.1 透过示例看消息中间件对应用的解耦 1.1.1.通过服务调用让其他系统感知事件发生的方式 假设我们要做一个用户登录系统,其中需要支持的一个功能是,用户登录成功 ...

  7. Luogu-3250 [HNOI2016]网络

    Luogu-3250 [HNOI2016]网络 题面 Luogu-3250 题解 CDQ分治...这个应该算是整体二分吧 二分重要度,按照时间从小到大加入大于重要度的边 对于一个询问,如果经过这个点的 ...

  8. Search insert position, 查找插入位置

    问题描述:给定一个有序序列,如果找到target,返回下标,如果找不到,返回插入位置. 算法分析:依旧利用二分查找算法. public int searchInsert(int[] nums, int ...

  9. python之websocket

    一.websocket WebSocket协议是基于TCP的一种新的协议.WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符.它实现了浏览器与服务器全双工 ...

  10. Swagger实践和总结

    Swagger学习和实践 最近安装并使用了一下Swagger-ui.Swagger-editor和Swagger-codegen,感觉还不错. Swagger 是一个规范和完整的框架,用于生成.描述. ...