日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Rust实现线段树和懒标记

發布時間:2024/1/2 windows 31 coder
生活随笔 收集整理的這篇文章主要介紹了 Rust实现线段树和懒标记 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

參考各家代碼,用Rust實現了線段樹和懶標記。

由于使用了泛型,很多操作都要用閉包自定義實現。

看代碼。

// 線段樹定義
pub struct SegmentTree<T: Clone>
{
    pub data: Vec<T>,
    tree: Vec<Option<T>>,
    marker: Vec<T>,                               //懶標記。
    query_op: Box<dyn Fn(T, T) -> T>, //查詢時,對所有查詢元素做的操作。比如加法,就是求區間的所有元素的和。
    marker_marker_op: Box<dyn Fn(T, T) -> T>, //marker加到marker上時,對marker的操作。通常我們要marker[i] += p; 來更新標記,但是泛型實現不了,并且考慮到有些用戶有別的需求,所以用閉包包裝。
    marker_t_op: Box<dyn Fn(T, T) -> T>, //marker應用到T時,對T的操作??紤]到有些用戶有別的需求,所以用閉包包裝。
    marker_mul_usize: Box<dyn Fn(T, usize) -> T>, //marker乘usize的方法。這個沒法通過要求滿足Mul trait自動實現。由于使用了泛型,連乘法都要交給閉包實現。。。
}

impl<T: Clone + Default + Copy + PartialEq> SegmentTree<T> {
    pub fn new(
        data: Vec<T>,
        query_op: Box<dyn Fn(T, T) -> T>,
        marker_marker_op: Box<dyn Fn(T, T) -> T>,
        marker_t_op: Box<dyn Fn(T, T) -> T>,
        marker_mul_usize: Box<dyn Fn(T, usize) -> T>,
    ) -> Self {
        let data_len = data.len();
        let mut tr = Self {
            data,
            marker: vec![T::default(); 4 * data_len], //四倍原數據大小
            tree: vec![None; 4 * data_len],           //四倍原數據大小
            query_op,
            marker_marker_op,
            marker_t_op,
            marker_mul_usize,
        };
        tr.build();
        tr
    }

    #[inline]
    pub fn get(&self, index: usize) -> Option<&T> {
        self.data.get(index)
    }

    #[inline]
    pub fn len(&self) -> usize {
        self.data.len()
    }

    #[inline]
    fn left_child(index: usize) -> usize {
        2 * index + 1
    }

    #[inline]
    fn right_child(index: usize) -> usize {
        2 * index + 2
    }

    #[inline]
    fn build(&mut self) {
        self.build_segment_tree(0, 0, self.data.len() - 1);
    }

    // 遞歸Build
    fn build_segment_tree(&mut self, tree_index: usize, left: usize, right: usize) {
        if left == right {
            self.tree[tree_index] = Some(self.data[left]);
            return;
        }
        let left_tree_index = Self::left_child(tree_index);
        let right_tree_index = Self::right_child(tree_index);
        let mid = (right - left) / 2 + left;
        self.build_segment_tree(left_tree_index, left, mid);
        self.build_segment_tree(right_tree_index, mid + 1, right);
        // 左右子樹數據處理方式
        if let Some(l) = self.tree[left_tree_index] {
            if let Some(r) = self.tree[right_tree_index] {
                self.tree[tree_index] = Some((self.query_op)(l, r))
            }
        }
    }

    // 返回對線段樹的全部元素做query_op操作的結果
    #[inline]
    pub fn query_all(&mut self) -> T {
        self.recursion_query(0, self.data.len() - 1, 0, 0, self.data.len() - 1)
    }

    // 返回對線段樹的[l..r]范圍全部元素做query_op操作的結果
    pub fn query(&mut self, l: usize, r: usize) -> Result<T, &'static str> {
        if l > self.data.len() || r > self.data.len() || l > r {
            return Err("索引錯誤");
        }
        if l == r {
            return Ok(self.data[l]);
        }
        Ok(self.recursion_query(l, r, 0, 0, self.data.len() - 1))
    }

    // 在index表示的[current_left,current_right]范圍中查詢[l..r]值
    fn recursion_query(
        &mut self,
        l: usize,
        r: usize,
        index: usize,
        current_left: usize,
        current_right: usize,
    ) -> T {
        if l > current_right || r < current_left {
            return T::default();
        }
        if l == current_left && r == current_right {
            if let Some(d) = self.tree[index] {
                if l == r {
                    self.data[l] = d;
                }
                return d;
            }
            return T::default();
        }
        self.push_down(index, current_right - current_left + 1);
        let mid = current_left + (current_right - current_left) / 2;
        if l >= mid + 1 {
            return self.recursion_query(l, r, Self::right_child(index), mid + 1, current_right);
        } else if r <= mid {
            return self.recursion_query(l, r, Self::left_child(index), current_left, mid);
        }
        let l_res = self.recursion_query(l, mid, Self::left_child(index), current_left, mid);
        let r_res =
            self.recursion_query(mid + 1, r, Self::right_child(index), mid + 1, current_right);
        (self.query_op)(l_res, r_res)
    }

    // 更新index為val
    pub fn set(&mut self, index: usize, val: T) -> Result<(), &'static str> {
        if index >= self.data.len() {
            return Err("索引超過線段樹長度");
        }
        // 更新數據
        self.data[index] = val;
        // 遞歸更新樹
        self.recursion_set(0, 0, self.data.len() - 1, index, val);
        Ok(())
    }

    // 遞歸更新樹
    fn recursion_set(&mut self, index_tree: usize, l: usize, r: usize, index: usize, val: T) {
        if l == r {
            self.tree[index_tree] = Some(val);
            return;
        }
        let mid = l + (r - l) / 2;
        let left_child = Self::left_child(index_tree);
        let right_child = Self::right_child(index_tree);
        if index >= mid + 1 {
            self.recursion_set(right_child, mid + 1, r, index, val);
        } else {
            self.recursion_set(left_child, l, mid, index, val);
        }
        // 左右子樹數據求和
        if let Some(l_d) = self.tree[left_child] {
            if let Some(r_d) = self.tree[right_child] {
                self.tree[index_tree] = Some((self.query_op)(l_d, r_d));
            }
        }
    }

    // 應用所有懶標記到data數組上
    #[inline]
    pub fn apply_marker_all(&mut self) {
        self.apply_marker_lr(0, self.data.len() - 1);
    }

    // 應用懶標記到[l:r]數據范圍
    #[inline]
    pub fn apply_marker_lr(&mut self, l: usize, r: usize) {
        self.apply_marker(l, r, 0, 0, self.data.len() - 1);
    }

    fn apply_marker(
        &mut self,
        l: usize,
        r: usize,
        index: usize,
        current_l: usize,
        current_r: usize,
    ) {
        if current_l > r || current_r < l || r >= self.data.len() {
            return; // 區間無交集
        } else {
            // 與目標區間有交集,但不包含于其中
            if current_l == current_r {
                if let Some(d) = self.tree[index] {
                    self.data[current_l] = d;
                }
                return;
            }
            let mid = (current_l + current_r) / 2;
            self.push_down(index, current_r - current_l + 1);
            self.apply_marker(l, r, Self::left_child(index), current_l, mid); // 遞歸地往下尋找
            self.apply_marker(l, r, Self::right_child(index), mid + 1, current_r);
            self.tree[index] = Some((self.query_op)(
                self.tree[Self::left_child(index)].unwrap(),
                self.tree[Self::right_child(index)].unwrap(),
            ));
            // 根據子節點更新當前節點的值
        }
    }
    #[inline]
    pub fn update_interval(&mut self, l: usize, r: usize, delta: T) {
        self.update(l, r, delta, 0, 0, self.data.len() - 1);
    }

    // 傳遞marker到下級
    fn push_down(&mut self, index: usize, len: usize) {
        self.marker[Self::left_child(index)] =
            (self.marker_marker_op)(self.marker[index], self.marker[Self::left_child(index)]); // 標記向下傳遞
        self.marker[Self::right_child(index)] =
            (self.marker_marker_op)(self.marker[index], self.marker[Self::right_child(index)]);
        if self.tree[Self::left_child(index)].is_some() {
            self.tree[Self::left_child(index)] = Some((self.marker_t_op)(
                (self.marker_mul_usize)(self.marker[index], len - (len / 2)),
                self.tree[Self::left_child(index)].unwrap(),
            ));
        }
        if self.tree[Self::right_child(index)].is_some() {
            self.tree[Self::right_child(index)] = Some((self.marker_t_op)(
                (self.marker_mul_usize)(self.marker[index], len / 2),
                self.tree[Self::right_child(index)].unwrap(),
            ));
        }
        self.marker[index] = T::default(); // 清除標記
    }

    fn update(
        &mut self,
        l: usize,
        r: usize,
        delta: T,
        index: usize,
        current_l: usize,
        current_r: usize,
    ) {
        if current_l > r || current_r < l {
            return; // 區間無交集
        } else if current_l >= l && current_r <= r {
            // 當前節點對應的區間包含在目標區間中
            if self.tree[index].is_some() {
                // 更新當前區間的值
                self.tree[index] = Some((self.query_op)(
                    self.tree[index].unwrap(),
                    (self.marker_mul_usize)(delta, current_r - current_l + 1),
                ));
            }
            // 如果不是葉子節點
            if current_r > current_l {
                // 給當前區間打上標記
                self.marker[index] = (self.marker_marker_op)(delta, self.marker[index]);
            }
        } else {
            // 與目標區間有交集,但不包含于其中
            let mid = (current_l + current_r) / 2;
            self.push_down(index, current_r - current_l + 1);
            self.update(l, r, delta, Self::left_child(index), current_l, mid); // 遞歸地往下尋找
            self.update(l, r, delta, Self::right_child(index), mid + 1, current_r);
            self.tree[index] = Some((self.query_op)(
                self.tree[Self::left_child(index)].unwrap(),
                self.tree[Self::right_child(index)].unwrap(),
            )); // 根據子節點更新當前節點的值
        }
    }
}

fn main() {
    let mut tr: SegmentTree<i32> = SegmentTree::new(
        vec![1, 3, 4, 0, 0, 4, 5, 0],
        Box::new(|a, b| a + b),
        Box::new(|a, b| a + b),
        Box::new(|a, b| a + b),
        Box::new(|a, b| a * (b as i32)),
    );
    let _ = tr.set(1, 2); //點更新,即把data[1]設為2
    tr.update_interval(0, 2, -1); //區間更新,即[0:2]每個元素減1
    tr.update_interval(1, 3, 2); //區間更新,即[1:3]每個元素加2
    tr.apply_marker_all(); //應用全部marker到data數組
    println!("{}", tr.query_all()); //輸出19,即全部元素的和
    println!("{:?}", tr.data); //輸出[0, 3, 5, 2, 0, 4, 5, 0]
}

做一道題驗證一下這個線段樹的正確性,直接看我寫的1589. 所有排列中的最大和題解即可(雖然這道題用差分數組最快,但是作為線段樹驗證還是很方便的)。

總結

以上是生活随笔為你收集整理的Rust实现线段树和懒标记的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。