当前位置: 首页 > news >正文

ODT/珂朵莉树 入门

主打一个看到别人学什么我学什么,反正什么也不会。

什么是 ODT

是一种数据结构

类比线段树的话,他的每一条线段(一个基本单位)记录了相同 "颜色" 的东西的信息
使用一个结构体的 \(set\),记录 区间 \([l,r]\) 的信息都为 \(k\)

时间复杂度

随机数据可能是 \(O(n)\) 的,一般可以认为是 \(O(nlogn)\) ,但有时也可以卡到 \(nlog^2n\)
不知道,差不多用就是了

解决什么问题

根据其特性,可以解决区间 \(k\) 大,区间元素幂的和...
还有什么做到了再说.....

ODT 怎么维护

核心是 Split 操作

对于一个 \(pos\) 的修改,找到覆盖 \(pos\) 的区间 \([l,r]\) ,将他分开变成 \([l,pos-1],[pos,r]\) ,然后返回 \([pos,r]\) 区间的迭代器

区间修改操作

\([l,r]\) 赋值为 \(x\)\(split(r+1)\) ,再 \(split(l)\)
原因就是 \(split(l)\) 会影响后面的值
然后删掉两个迭代器中间的信息,全部变成一个 \([l,r],x\)

所以我们得到模版代码,有一些不常用的东西

模版

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define IT set<node>::iterator
struct node{int l,r;mutable ll v;//mutable就是你在用迭代器访问的时候也可以直接赋值 bool operator < (const node &a)const {return l<a.l;}
};
set<node> s;
IT split(int pos){IT it=s.lower_bound(node{pos,0,0});if(it!=s.end()&&is->l==pos)return it;it--;if((it->r)<pos)return s.end();//写指针注意加括号int l=it->l,r=it->r;ll v=it->v;s.erase(it);s.insert(node{l,pos-1,v});return s.insert(node{pos,r,v}).first;//set.insert返回一个 pair :first指向插入后该元素的迭代器,second则为bool表示插入是否成功。 
}
void upd(int l,int r,int x){IT itr=split(r+1);//因为我们要拆出 $[l,r]$ 而split会拆出 [l,pos-1]所以应该是r+1IT itl=split(l);s.erase(itl,itr);//表示删除两迭代器中间的所有元素s.insert(node{l,r,x}); 
} 

例题

对于 \(ODT\) 的题,答案的维护一般就在 \(upd\) 函数里,没有固定模版

CF915E

非工作日为 \(0\) ,工作日为 \(1\) ,就是维护全局和,那就每次减去旧区间和加上新的

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
#define ll long long
#define IT set<node>::iterator
int n,q;
struct node{int l,r;mutable ll v;bool operator <  (const node &a)const {return l<a.l;}
};
set<node>s;
IT split(int pos){IT it=s.lower_bound(node{pos,0,0});if(it!=s.end()&&it->l==pos)return it;it--;if(it->r<pos)return s.end();int l=it->l,r=it->r;ll v=it->v;s.erase(it);s.insert(node{l,pos-1,v});return s.insert(node{pos,r,v}).first;
}
ll ans=0;
void upd(int l,int r,int x){IT itr=split(r+1),itl=split(l);for(IT it=itl;it!=itr;it++)ans-=1ll*(it->v)*((it->r)-(it->l)+1);ans+=1ll*(r-l+1)*x;s.erase(itl,itr);s.insert(node{l,r,x}); 
}
signed main(){ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>n>>q;ans=n;s.insert(node{1,n,1});while(q--){int l,r,x;cin>>l>>r>>x;upd(l,r,x-1);cout<<ans<<"\n";}return 0;
}
http://www.jsqmd.com/news/291/

相关文章:

  • 博客更新公告
  • 在AI技术快速实现功能的时代,挖掘新需求成为关键突破点——某知名游戏资源分析工具需求洞察
  • 蜜罐
  • 【光照】[漫反射]UnityURP兰伯特有光照衰减吗?
  • 手把手带你从零开始实现一个编译器
  • prenotami.esteri.it 意大利签证预约error
  • 绯闻女孩不只会八卦:从“验明正身”到“抓内鬼”,Gossip的进阶玩法
  • reLeetCode 热题 100- 15. 三数之和 - MKT
  • US$94 T300 Key Programmer Spanish Blue 2016 V16.8 Full
  • US$99 VVDI MB NEC Key Adaptor
  • testuserpython
  • Python-Pathlib库
  • 反省
  • US$34 Bluetooth Adapter for Yanhua Mini ACDP
  • global 设置内核源码在线浏览
  • [Nacos/Docker/MCP] Nacos 3.x : 为 AI MCP 而生
  • 牛客周赛 Round 108 CDEF题解
  • [LeetCode] 3484. Design Spreadsheet
  • Redis的使用问题
  • AIGC拾遗:Flash Attention
  • 深度好文-风雨飘摇信竞路
  • Python-CSV库
  • C++小白修仙记_LeetCode刷题_位运算
  • C++小白修仙记_LeetCode刷题_双指针
  • 前路漫漫亦灿灿 往事堪堪亦澜澜
  • 设计模式(C++)详解—单例模式(2) - 指南
  • 使用uv和pycharm搭建python开发环境
  • lc1032-字符流
  • 八股整理xdsm - 教程
  • C++小白修仙记_LeetCode刷题_哈希表