ODT简介

ODT(old driver tree 老驱动树)又名珂朵莉树是由codeforcescodeforcescodeforces上一位叫做ODTODTODT的用户提出的一种基于平衡树的暴力数据结构。

这个数据结构的玄妙之处在于它
并没有稳定的时间复杂度
,因此只有在数据随机/水的情况下才会有较好的表现。

实现前提&&实现原理

前提是必须要有区间覆盖操作且数据较随机/水

实现原理:将元素相同的区间推平一起处理,即如果区间[l,r][l,r][l,r]中的所有数[al,al+1...ar][a_l,a_{l+1}...a_r][al​,al+1​...ar​]全部相同的话就将这个区间的信息用一个节点表示。

从上述描述可以看出这个数据结构是非常暴力玄学的

初始化

然后对于每段区间我们可以用一个三元组[l,r,v][l,r,v][l,r,v]来表示它的左/右端点和整个区间的值,然后对于这些区间的信息可以用一个setsetset来维护。

下面是ODTODTODT节点的初始化代码:

struct Node{
	int l,r;
	mutable int v;
	Node(int l,int r=-1,int v=0):l(l),r(r),v(v){}
	friend inline bool operator<(const Node&a,const Node&b){
		return a.l<b.l;
	}
};
set<Node>S;
typedef set<Node>::iterator It;

然后我们要谈谈ODTODTODT两个重要的操作splitsplitsplit和assignassignassign

split操作

ODTODTODT的splitsplitsplit函数split(pos)split(pos)split(pos)表示把pospospos所在的这个区间[l,r,v][l,r,v][l,r,v]分成[l,pos−1,v][l,pos-1,v][l,pos−1,v]和[pos,r,v][pos,r,v][pos,r,v]并且返回后者的迭代器。

实现很简单直接lowerboundlower_boundlowerb​ound出pospospos所在的区间然后加几个小特判。

代码:

inline It split(int pos){
	It it=S.lower_bound(pos);
	if(it!=S.end()&&it->l==pos)return it;
	--it;
	if(pos>it->r)return S.end();
	int l=it->l,r=it->r,v=it->v;
	S.erase(it);
	S.insert(Node(l,pos-1,v));
	return S.insert(Node(pos,r,v)).first;
}

assign操作

ODTODTODT最核心的操作assignassignassign,assign(l,r,v)assign(l,r,v)assign(l,r,v)表示把区间[l,r][l,r][l,r]全部赋值为vvv并且会将这r−l+1r-l+1r−l+1个点合并成一个ODTODTODT节点插入到ODTODTODT中,由于数据随机的时候ODTODTODT中节点会快速减少,因此ODTODTODT复杂度此时十分接近O(nlogn)O(nlog_n)O(nlogn​)

具体实现可以通过上面提到的splitsplitsplit函数。

代码:

inline void assign(int l,int r,int v){
	It R=split(r+1),L=split(l);
	S.erase(L,R),S.insert(Node(l,r,v));
}

其它操作

至此,与ODTODTODT相关的操作已经基本讲完了。

剩下的操作与ODTODTODT本身关系并不大,相当于就是遍历每一个ODTODTODT节点暴力进行修改和查询。

区间第k小

代码:

typedef set<Node>iterator It;
typedef pair<long long,int> pli;
vector<pli>q;
inline int rank(int l,int r,int kth){
    It R=split(r+1),L=split(l);
    q.clear();
    for(It it=L;it!=R;++it)q.push_back(pli(it->v,it->r-it->l+1));
    sort(q.begin(),q.end());
    for(ri i=0;i<q.size();++i){
        kth-=q[i].second;
        if(kth<=0)return q[i].first;
    }
    return -1;
}

区间加

代码:

inline void add(int l,int r,int v){
    It L=split(l),R=split(r+1);
    for(It it=L;it!=R;++it)(it->v)+=v;
}

区间所有数的k次方和

代码:

typedef long long ll;
inline ll query(int l,int r,int k,ll mod){
    ll ret=0;
    It L=split(l),R=split(r+1);
    for(It it=L;it!=R;++it)ret=(ret+(ll)(it->r-it->l+1)*ksm(it->v,k,mod)%mod)%mod;
    return ret;
}

几道水题

codeforces896Ccodeforces896Ccodeforces896C

codeforces915Ecodeforces915Ecodeforces915E

codeforces343Dcodeforces343Dcodeforces343D

bzoj4592bzoj4592bzoj4592

洛谷2787洛谷2787洛谷2787

ODT(old driver tree)详解(带例题)的更多相关文章

  1. Apache的配置详解 带图

    对Apache 的 Http.conf 各项配置详解 1.01 ServerRoot 配置 [ServerRoot "" 主要用于指定 Apache 的安装路径,此选项参数值在安装 ...

  2. [转] 关于Struts-JSON配置(详解带实例struts2的json数据支持)

    关于Struts-JSON的提高开发效率 一.JSON是什么? :JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解 析和 ...

  3. 【算法】关于图论中的最小生成树(Minimum Spanning Tree)详解

    本节纲要 什么是图(network) 什么是最小生成树 (minimum spanning tree) 最小生成树的算法 什么是图(network)? 这里的图当然不是我们日常说的图片或者地图.通常情 ...

  4. dsu on tree详解

    这个算法还是挺人性化的,没有什么难度 就是可能看起来有点晕什么的. 大体 思想是 利用重链刨分来优化子树内部的查询. 考虑一个问题要对每个子树都要询问一次.我们暴力显然是\(n^2\)的. 考虑一下优 ...

  5. c#操作MangoDB 之MangoDB CSharp Driver驱动详解

    序言 MangoDB CSharp Driver是c#操作mongodb的官方驱动. 官方Api文档:http://api.mongodb.org/csharp/2.2/html/R_Project_ ...

  6. BIT 树状数组 详解 及 例题

    (一)树状数组的概念 如果给定一个数组,要你求里面所有数的和,一般都会想到累加.但是当那个数组很大的时候,累加就显得太耗时了,时间复杂度为O(n),并且采用累加的方法还有一个局限,那就是,当修改掉数组 ...

  7. 二叉查找树(binary search tree)详解

    二叉查找树(Binary Search Tree),也称二叉排序树(binary sorted tree),是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有结点的值均小于 ...

  8. C#调用存储过程详解(带返回值、参数输入输出等)

    CREATE PROCEDURE [dbo].[GetNameById] @studentid varchar(8), @studentname nvarchar(50) OUTPUT AS BEGI ...

  9. BTree和B+Tree详解

    https://www.cnblogs.com/vianzhang/p/7922426.html B+树索引是B+树在数据库中的一种实现,是最常见也是数据库中使用最为频繁的一种索引.B+树中的B代表平 ...

随机推荐

  1. PAT1066(AVL树)

    An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...

  2. Python+Selenium学习--简单对象定位

    场景 测试对象的定位和操作是webdriver的核心内容,其中操作又是建立在定位的基础之上,因此对象定位就越发显得重要了. 定位对象的目的一般有下面几种 操作对象 获得对象的属性,如获得测试对象的cl ...

  3. OSPF网络类型不一致路由无法计算的问题

    晚上割接,远端的ASR9001-s网络类型为广播类型,本端为6509-e,网络接口类型修改成p2p后,OSPF邻居关系建立,但是路由无法计算.

  4. 二次注入的学习--Buy Flag(http://10.112.68.215:10002)

    这次有做一个二次注入的天枢CTF题目,算是完整地理解了一遍注入的知识.来,启航.   1.判断注入点     经过对题目的实践分析,知道注册时需要输入年龄大于18岁,但在登录后界面,年龄因为太大不能接 ...

  5. vue 使用scss

    使用vue-cli模板创建的项目中,使用scss步骤 1. cmd命令: cnpm  install sass-loader --save-dev cnpm install node-sass --s ...

  6. 六.Spring与RabbitMQ集成--HelloWorld

    spring对RabbitMQ做了很好的集成,我们称之为spring AMQP,其官方文档写得十分详尽,文档地址:https://docs.spring.io/spring-amqp/referenc ...

  7. DBCO

    实现SAP连接外部数据库 也可用SM30维护DBCON的内容 SAP提供了对原生sql的操作,主要有以下几个类组成: CL_SQL_STATEMENT - Execution of SQL State ...

  8. Spring <context:annotation-config> 和 <context:component-scan> 区别

    一篇很不错的文章,看到就是赚到Get.... https://www.cnblogs.com/leiOOlei/p/3713989.html 说白了 :<context:component-sc ...

  9. ScrollView嵌套ListView,禁止ListView的滚动,只让ScrollView可以滚动

    自定义ListView,xml布局文件中使用该自定义的ListView public class NoScrollListview extends ListView{ public NoScrollL ...

  10. php libev扩展使用

    在WorkerMan源码分析 - 实现最简单的原型文章中提到了libevent网络库,前者和libev都是事件驱动编程库高性能.简单说libev对libevent做了改进和精简.libevent使用全 ...