时间序列线段树
来源:互联网 发布:java中io流详解视频 编辑:程序博客网 时间:2024/06/06 01:41
可以以O(log2(n))的时间复杂度处理任何日期序列的区间点修改和统计问题,例如维护区间和、区间内最大最小值平均数、区间内最大公因数、区间内的逆序数个数。以下为一个维护时间序列RMQ(区间最小值)的例子
<?php/** * Description: 时间序列线段树 * */define("INFINITE", pow(2, 64));class TSSegTree { private $begin; private $end; private $segTree = array(); private $delay_mark = array(); public static $debug_count = 0; public function __construct($begin, $end, $init_arr=array()) { $this->begin = $begin; $this->end = $end; $this->build(0, $this->begin, $this->end, $init_arr); } private function lchild($father) { return $father * 2 + 1; } private function rchild($father) { return $father * 2 + 2; } // 取两个日期的中间日期 private function middate($begin, $end) { $interval = (strtotime($end)-strtotime($begin)) / 86400; $interval = intval($interval / 2); return $this->nextnday($begin, $interval); } private function nextnday($date, $n=1) { $operator = $n >= 0? '+' : '-'; return date('Y-m-d', strtotime("{$date} {$operator}{$n} day")); } // 更新当前节点值 public function pushUp($root) { $lchild = $this->lchild($root); $rchild = $this->rchild($root); $this->segTree[$root] = min($this->segTree[$lchild], $this->segTree[$rchild]); } // 构建线段树 public function build($root = 0, $begin, $end, $init_arr=array()) { $this->delay_mark[$root] = 0; if (strtotime($begin) == strtotime($end)) { $this->segTree[$root] = $init_arr[$begin]; } else { $mid = $this->middate($begin, $end); $this->build($root * 2 + 1, $begin, $mid, $init_arr); $this->build($root * 2 + 2, $this->nextnday($mid), $end, $init_arr); $this->pushUp($root); } } // 区间查询 public function query($root, $nbegin, $nend, $qbegin, $qend) { if (strtotime($qbegin) > strtotime($nend) || strtotime($qend) < strtotime($nbegin) ) { return INFINITE; } if (strtotime($qbegin) <= strtotime($nbegin) && strtotime($qend) >= strtotime($nend) ) { return $this->segTree[$root]; } $this->pushDown($root); $mid = $this->middate($nbegin, $nend); return min($this->query($this->lchild($root), $nbegin, $mid, $qbegin, $qend), $this->query($this->rchild($root), $this->nextnday($mid), $nend, $qbegin, $qend )); } // 单节点更新 public function updateNode($root, $nbegin, $nend, $index, $val) { if (strtotime($nbegin) == strtotime($nend)) { if (strtotime($index) == strtotime($nbegin)) { $this->segTree[$root] += $val; // or other update method } return; } $mid = $this->middate($nbegin, $nend); if (strtotime($index) <= strtotime($mid)) { $this->updateNode($this->lchild($root), $nbegin, $mid, $index, $val); } else { $this->updateNode($this->rchild($root), $this->nextnday($mid), $nend, $index, $val); } $this->pushUp($root); return; } // 向子节点更新标志域 public function pushDown($root) { if ($this->delay_mark[$root] != 0) { $this->delay_mark[$this->lchild($root)] += $this->delay_mark[$root]; $this->delay_mark[$this->rchild($root)] += $this->delay_mark[$root]; // change value $this->segTree[$this->lchild($root)] += $this->delay_mark[$root]; $this->segTree[$this->rchild($root)] += $this->delay_mark[$root]; $this->delay_mark[$root] = 0; } } // 区间更新 public function updateRange($root, $nbegin, $nend, $ubegin, $uend, $val) { if ($ubegin > $nend || $uend < $nbegin) { return; } if ($ubegin <= $nbegin && $uend >= $nend) { $this->segTree[$root] += $val; $this->delay_mark[$root] += $val; return; } $this->pushDown($root); $mid = $this->middate($nbegin, $nend); $this->updateRange($this->lchild($root), $nbegin, $mid, $ubegin, $uend, $val); $this->updateRange($this->rchild($root), $this->nextnday($mid), $nend, $ubegin, $uend, $val); $this->pushUp($root); } // 输出值 public function dumpTree($root, $begin, $end) { echo "{$begin} ~ {$end} : root: {$root}, val: {$this->segTree[$root]} "; echo "\r\n"; if (strtotime($begin) == strtotime($end)) { return; } else { $mid = $this->middate($begin, $end); $this->dumpTree($this->lchild($root), $begin, $mid); $this->dumpTree($this->rchild($root), $this->nextnday($mid), $end); } return; }}function test() { $dataset = array( '2017-01-01' => 6, '2017-01-02' => 2, '2017-01-03' => 5, '2017-01-04' => 8, '2017-01-05' => 12, '2017-01-06' => 9, '2017-01-07' => 10, '2017-01-08' => 11 ); $tree = new TSSegTree('2017-01-01', '2017-01-08', $dataset); $tree->updateNode(0, '2017-01-01', '2017-01-08', '2017-01-04', 2); $result = $tree->query(0, '2017-01-01', '2017-01-08', '2017-01-03', '2017-01-06'); echo $result; $tree->dumpTree(0, '2017-01-01', '2017-01-08'); $tree->updateRange(0, '2017-01-01', '2017-01-08', '2017-01-03', '2017-01-06', -1); $result = $tree->query(0, '2017-01-01', '2017-01-08', '2017-01-03', '2017-01-06'); echo $result; echo "\r\n"; $tree->dumpTree(0, '2017-01-01', '2017-01-08');}test();?>
0 0
- 时间序列线段树
- 【线段树】序列操作
- 【SCOI2010】【线段树】序列操作
- 【bzoj2962】【序列操作】【线段树】
- bzoj1858序列操作 线段树
- 【BZOJ4540】【Hnoi2016】序列 线段树
- 线段树 [AHOI2011维护序列]
- 【SCOI2010】序列操作 线段树
- 序列操作(线段树)
- bzoj1095 线段树括号序列
- bzoj2962 序列操作 线段树
- 【bzoj4553】【Tjoi2016】【Heoi2016】【序列】【树套树】【线段树套线段树】
- uestc 1546 括号序列 区间线段树
- 【COGS】1272 [AHOI2009] 行星序列 线段树
- BZOJ 1858 SCOI2010 序列操作 线段树
- 【BZOJ1858】[Scoi2010]序列操作 线段树
- bzoj 1858 序列操作(线段树)
- bzoj 2962 序列操作(线段树)
- HIVE 语句执行 中报错:Java heap space
- ThreadPoolExecutor使用和思考(上)-线程池大小设置与BlockingQueue的三种实现区别
- 在c++中,如何利用try捕获SEH异常
- 数据挖掘整理(三)
- 2016个人年终总结
- 时间序列线段树
- 【项目管理和构建】十分钟教程,eclipse配置maven + 创建maven项目(三)
- 重磅!悬镜团队发布国内首个基于机器学习技术的威胁检测引擎Xmaze
- 资料整理
- 解决on失效
- 2017年计划
- 安装Photoshop CS6失败:FATAL: Payload 'Camera Profiles Installer ...information not found in Media_db.
- 前端工程化体系
- JAVA之输出一个四位整数的各位数字之和