From d8555c5e43e302a47b291de733fca12732855017 Mon Sep 17 00:00:00 2001 From: Sreekar Reddy Date: Mon, 30 Jun 2025 01:29:33 +0530 Subject: [PATCH 1/3] Added Trie and Segment Tree (with Lazy Propagation) --- .../src/segment_tree/README.md | 51 ++++++++++++ .../src/segment_tree/segment_tree.cpp | 59 ++++++++++++++ .../src/segment_tree/segment_tree_lazy.cpp | 80 +++++++++++++++++++ code/data_structures/src/trie/README.md | 33 ++++++++ code/data_structures/src/trie/trie.cpp | 68 ++++++++++++++++ 5 files changed, 291 insertions(+) create mode 100644 code/data_structures/src/segment_tree/README.md create mode 100644 code/data_structures/src/segment_tree/segment_tree.cpp create mode 100644 code/data_structures/src/segment_tree/segment_tree_lazy.cpp create mode 100644 code/data_structures/src/trie/README.md create mode 100644 code/data_structures/src/trie/trie.cpp diff --git a/code/data_structures/src/segment_tree/README.md b/code/data_structures/src/segment_tree/README.md new file mode 100644 index 0000000000..cefe3db03b --- /dev/null +++ b/code/data_structures/src/segment_tree/README.md @@ -0,0 +1,51 @@ +# Segment Tree + +A **Segment Tree** is a binary tree used for efficient range queries and updates on arrays. + +This folder contains: +- Basic Segment Tree implementation +- Segment Tree with Lazy Propagation (for range updates) + +--- + +## Files + +| File | Description | +|----------------------------|---------------------------------------------------| +| `segment_tree.cpp` | Point updates and range sum queries | +| `segment_tree_lazy.cpp` | Supports range updates using lazy propagation | + +--- + +## Supported Operations + +### `segment_tree.cpp` +- Build from array +- Point update +- Range sum query + +### `segment_tree_lazy.cpp` +- Build from array +- **Range update** +- Range sum query with **lazy propagation** + +--- + +## Time Complexity + +| Operation | Time | +|------------------|------------| +| Build Tree | O(n) | +| Point Update | O(log n) | +| Range Query | O(log n) | +| Range Update | O(log n) *(with lazy)* | + +--- + +## Sample Usage (from `main()`) + +```cpp +int arr[] = {1, 3, 5, 7, 9, 11}; +build(0, 5, 1); // Builds segment tree +cout << query(1, 3, 1); // Queries sum in range [1, 3] +update(1, 10, 1, 3, 0); // Range update in segment_tree_lazy.cpp diff --git a/code/data_structures/src/segment_tree/segment_tree.cpp b/code/data_structures/src/segment_tree/segment_tree.cpp new file mode 100644 index 0000000000..9d6d1e8f33 --- /dev/null +++ b/code/data_structures/src/segment_tree/segment_tree.cpp @@ -0,0 +1,59 @@ +// segment_tree.cpp +// Basic Segment Tree for range sum and point updates + +#include +using namespace std; + +const int N = 1e5; +int seg[4 * N], a[N]; + +// Build the segment tree +void build(int l, int r, int idx) { + if (l == r) { + seg[idx] = a[l]; + return; + } + int mid = (l + r) / 2; + build(l, mid, 2 * idx); + build(mid + 1, r, 2 * idx + 1); + seg[idx] = seg[2 * idx] + seg[2 * idx + 1]; +} + +// Point update: a[pos] += val +void update(int l, int r, int idx, int pos, int val) { + if (l == r) { + seg[idx] += val; + return; + } + int mid = (l + r) / 2; + if (pos <= mid) + update(l, mid, 2 * idx, pos, val); + else + update(mid + 1, r, 2 * idx + 1, pos, val); + seg[idx] = seg[2 * idx] + seg[2 * idx + 1]; +} + +// Query sum in range [ql, qr] +int query(int l, int r, int idx, int ql, int qr) { + if (qr < l || ql > r) + return 0; + if (ql <= l && r <= qr) + return seg[idx]; + int mid = (l + r) / 2; + return query(l, mid, 2 * idx, ql, qr) + query(mid + 1, r, 2 * idx + 1, ql, qr); +} + +int main() { + int n = 6; + int arr[] = {1, 3, 5, 7, 9, 11}; + for (int i = 0; i < n; ++i) + a[i] = arr[i]; + + build(0, n - 1, 1); + + cout << "Sum of range [1, 3]: " << query(0, n - 1, 1, 1, 3) << endl; + update(0, n - 1, 1, 1, 10); // a[1] += 10 + cout << "After update, sum of range [1, 3]: " << query(0, n - 1, 1, 1, 3) << endl; + + return 0; +} diff --git a/code/data_structures/src/segment_tree/segment_tree_lazy.cpp b/code/data_structures/src/segment_tree/segment_tree_lazy.cpp new file mode 100644 index 0000000000..e51898c89e --- /dev/null +++ b/code/data_structures/src/segment_tree/segment_tree_lazy.cpp @@ -0,0 +1,80 @@ +// segment_tree_lazy.cpp +// Segment Tree with Lazy Propagation for range updates + +#include +using namespace std; + +const int N = 1e5; +int seg[4 * N], lazy[4 * N], a[N]; + +// Build the tree +void build(int l, int r, int idx) { + if (l == r) { + seg[idx] = a[l]; + return; + } + int mid = (l + r) / 2; + build(l, mid, 2 * idx); + build(mid + 1, r, 2 * idx + 1); + seg[idx] = seg[2 * idx] + seg[2 * idx + 1]; +} + +// Push down lazy updates +void push(int l, int r, int idx) { + if (lazy[idx] != 0) { + seg[idx] += (r - l + 1) * lazy[idx]; + if (l != r) { + lazy[2 * idx] += lazy[idx]; + lazy[2 * idx + 1] += lazy[idx]; + } + lazy[idx] = 0; + } +} + +// Range update: add val to [ql, qr] +void update(int l, int r, int idx, int ql, int qr, int val) { + push(l, r, idx); + + if (qr < l || ql > r) + return; + if (ql <= l && r <= qr) { + lazy[idx] += val; + push(l, r, idx); + return; + } + + int mid = (l + r) / 2; + update(l, mid, 2 * idx, ql, qr, val); + update(mid + 1, r, 2 * idx + 1, ql, qr, val); + seg[idx] = seg[2 * idx] + seg[2 * idx + 1]; +} + +// Range query: sum in [ql, qr] +int query(int l, int r, int idx, int ql, int qr) { + push(l, r, idx); + + if (qr < l || ql > r) + return 0; + if (ql <= l && r <= qr) + return seg[idx]; + + int mid = (l + r) / 2; + return query(l, mid, 2 * idx, ql, qr) + query(mid + 1, r, 2 * idx + 1, ql, qr); +} + +int main() { + int n = 6; + int arr[] = {1, 3, 5, 7, 9, 11}; + for (int i = 0; i < n; ++i) + a[i] = arr[i]; + + build(0, n - 1, 1); + + cout << "Initial sum of [1, 3]: " << query(0, n - 1, 1, 1, 3) << endl; + + update(0, n - 1, 1, 1, 3, 10); // add 10 to range [1, 3] + + cout << "After range update, sum of [1, 3]: " << query(0, n - 1, 1, 1, 3) << endl; + + return 0; +} diff --git a/code/data_structures/src/trie/README.md b/code/data_structures/src/trie/README.md new file mode 100644 index 0000000000..c38128a4ca --- /dev/null +++ b/code/data_structures/src/trie/README.md @@ -0,0 +1,33 @@ +# Trie + +A **Trie** is a tree-based data structure used to store a dynamic set of strings, where keys are usually strings over an alphabet. + +--- + +## Operations + +- **Insert(string)** – Inserts a word into the Trie. +- **Search(string)** – Returns `true` if the word exists in the Trie. +- **StartsWith(prefix)** – Returns `true` if any word in the Trie starts with the given prefix. + +--- + +## Time Complexity + +Let **L** be the length of the word/prefix: +- Insert: `O(L)` +- Search: `O(L)` +- Prefix check: `O(L)` + +--- + +## Usage Example + +```cpp +Trie trie; +trie.insert("apple"); +trie.search("apple"); // true +trie.search("app"); // false +trie.startsWith("app"); // true +trie.insert("app"); +trie.search("app"); // true diff --git a/code/data_structures/src/trie/trie.cpp b/code/data_structures/src/trie/trie.cpp new file mode 100644 index 0000000000..e27f198e7a --- /dev/null +++ b/code/data_structures/src/trie/trie.cpp @@ -0,0 +1,68 @@ +// trie.cpp +// Trie implementation in C++ + +#include +using namespace std; + +struct TrieNode { + TrieNode* children[26]; + bool isEnd; + + TrieNode() { + isEnd = false; + fill(begin(children), end(children), nullptr); + } +}; + +class Trie { +public: + TrieNode* root; + + Trie() { + root = new TrieNode(); + } + + void insert(const string& word) { + TrieNode* node = root; + for (char ch : word) { + int i = ch - 'a'; + if (!node->children[i]) + node->children[i] = new TrieNode(); + node = node->children[i]; + } + node->isEnd = true; + } + + bool search(const string& word) { + TrieNode* node = root; + for (char ch : word) { + int i = ch - 'a'; + if (!node->children[i]) + return false; + node = node->children[i]; + } + return node->isEnd; + } + + bool startsWith(const string& prefix) { + TrieNode* node = root; + for (char ch : prefix) { + int i = ch - 'a'; + if (!node->children[i]) + return false; + node = node->children[i]; + } + return true; + } +}; + +int main() { + Trie trie; + trie.insert("apple"); + cout << "Search 'apple': " << trie.search("apple") << endl; // true + cout << "Search 'app': " << trie.search("app") << endl; // false + cout << "StartsWith 'app': " << trie.startsWith("app") << endl; // true + trie.insert("app"); + cout << "Search 'app': " << trie.search("app") << endl; // true + return 0; +} \ No newline at end of file From 301944fe90ad6eda039b6e7fd7203da4ae5bef21 Mon Sep 17 00:00:00 2001 From: Sreekar Reddy Date: Mon, 30 Jun 2025 01:44:26 +0530 Subject: [PATCH 2/3] Refactored Trie and Segment Tree to follow OpenGenus C++ Style Guide --- .../src/segment_tree/segment_tree.cpp | 110 ++++++++----- .../src/segment_tree/segment_tree_lazy.cpp | 147 +++++++++++------- code/data_structures/src/trie/trie.cpp | 91 ++++++----- 3 files changed, 204 insertions(+), 144 deletions(-) diff --git a/code/data_structures/src/segment_tree/segment_tree.cpp b/code/data_structures/src/segment_tree/segment_tree.cpp index 9d6d1e8f33..0c83e81f4a 100644 --- a/code/data_structures/src/segment_tree/segment_tree.cpp +++ b/code/data_structures/src/segment_tree/segment_tree.cpp @@ -1,59 +1,83 @@ -// segment_tree.cpp -// Basic Segment Tree for range sum and point updates +#include +#include -#include -using namespace std; +class SegmentTree { +public: + SegmentTree(const std::vector& data); -const int N = 1e5; -int seg[4 * N], a[N]; + void update(int index, int value); + int query(int left, int right); -// Build the segment tree -void build(int l, int r, int idx) { - if (l == r) { - seg[idx] = a[l]; - return; +private: + void build(int node, int start, int end); + void updateUtil(int node, int start, int end, int index, int value); + int queryUtil(int node, int start, int end, int left, int right); + + int size_; + std::vector tree_; + std::vector data_; +}; + +SegmentTree::SegmentTree(const std::vector& data) + : size_{static_cast(data.size())}, tree_(4 * size_), data_{data} { + build(1, 0, size_ - 1); +} + +void SegmentTree::build(int node, int start, int end) { + if (start == end) { + tree_[node] = data_[start]; + } else { + int mid = (start + end) / 2; + build(2 * node, start, mid); + build(2 * node + 1, mid + 1, end); + tree_[node] = tree_[2 * node] + tree_[2 * node + 1]; } - int mid = (l + r) / 2; - build(l, mid, 2 * idx); - build(mid + 1, r, 2 * idx + 1); - seg[idx] = seg[2 * idx] + seg[2 * idx + 1]; } -// Point update: a[pos] += val -void update(int l, int r, int idx, int pos, int val) { - if (l == r) { - seg[idx] += val; - return; +void SegmentTree::update(int index, int value) { + updateUtil(1, 0, size_ - 1, index, value); +} + +void SegmentTree::updateUtil(int node, int start, int end, int index, int value) { + if (start == end) { + data_[index] = value; + tree_[node] = value; + } else { + int mid = (start + end) / 2; + if (index <= mid) { + updateUtil(2 * node, start, mid, index, value); + } else { + updateUtil(2 * node + 1, mid + 1, end, index, value); + } + tree_[node] = tree_[2 * node] + tree_[2 * node + 1]; } - int mid = (l + r) / 2; - if (pos <= mid) - update(l, mid, 2 * idx, pos, val); - else - update(mid + 1, r, 2 * idx + 1, pos, val); - seg[idx] = seg[2 * idx] + seg[2 * idx + 1]; } -// Query sum in range [ql, qr] -int query(int l, int r, int idx, int ql, int qr) { - if (qr < l || ql > r) +int SegmentTree::query(int left, int right) { + return queryUtil(1, 0, size_ - 1, left, right); +} + +int SegmentTree::queryUtil(int node, int start, int end, int left, int right) { + if (right < start || end < left) { return 0; - if (ql <= l && r <= qr) - return seg[idx]; - int mid = (l + r) / 2; - return query(l, mid, 2 * idx, ql, qr) + query(mid + 1, r, 2 * idx + 1, ql, qr); + } + if (left <= start && end <= right) { + return tree_[node]; + } + + int mid = (start + end) / 2; + int sumLeft = queryUtil(2 * node, start, mid, left, right); + int sumRight = queryUtil(2 * node + 1, mid + 1, end, left, right); + return sumLeft + sumRight; } int main() { - int n = 6; - int arr[] = {1, 3, 5, 7, 9, 11}; - for (int i = 0; i < n; ++i) - a[i] = arr[i]; - - build(0, n - 1, 1); + std::vector data{1, 3, 5, 7, 9, 11}; + SegmentTree st(data); - cout << "Sum of range [1, 3]: " << query(0, n - 1, 1, 1, 3) << endl; - update(0, n - 1, 1, 1, 10); // a[1] += 10 - cout << "After update, sum of range [1, 3]: " << query(0, n - 1, 1, 1, 3) << endl; + std::cout << "Sum [1, 3]: " << st.query(1, 3) << "\n"; + st.update(1, 10); + std::cout << "Sum [1, 3] after update: " << st.query(1, 3) << "\n"; return 0; -} +} \ No newline at end of file diff --git a/code/data_structures/src/segment_tree/segment_tree_lazy.cpp b/code/data_structures/src/segment_tree/segment_tree_lazy.cpp index e51898c89e..0168055ecd 100644 --- a/code/data_structures/src/segment_tree/segment_tree_lazy.cpp +++ b/code/data_structures/src/segment_tree/segment_tree_lazy.cpp @@ -1,80 +1,111 @@ -// segment_tree_lazy.cpp -// Segment Tree with Lazy Propagation for range updates - -#include -using namespace std; - -const int N = 1e5; -int seg[4 * N], lazy[4 * N], a[N]; +#include +#include + +class SegmentTreeLazy { +public: + SegmentTreeLazy(const std::vector& data); + + void updateRange(int l, int r, int val); + int queryRange(int l, int r); + +private: + void build(int node, int start, int end); + void updateRangeUtil(int node, int start, int end, int l, int r, int val); + int queryRangeUtil(int node, int start, int end, int l, int r); + + int size_; + std::vector tree_; + std::vector lazy_; + std::vector data_; +}; + +SegmentTreeLazy::SegmentTreeLazy(const std::vector& data) + : size_{static_cast(data.size())}, + tree_(4 * size_), + lazy_(4 * size_, 0), + data_{data} { + build(1, 0, size_ - 1); +} -// Build the tree -void build(int l, int r, int idx) { - if (l == r) { - seg[idx] = a[l]; - return; +void SegmentTreeLazy::build(int node, int start, int end) { + if (start == end) { + tree_[node] = data_[start]; + } else { + int mid = (start + end) / 2; + build(2 * node, start, mid); + build(2 * node + 1, mid + 1, end); + tree_[node] = tree_[2 * node] + tree_[2 * node + 1]; } - int mid = (l + r) / 2; - build(l, mid, 2 * idx); - build(mid + 1, r, 2 * idx + 1); - seg[idx] = seg[2 * idx] + seg[2 * idx + 1]; } -// Push down lazy updates -void push(int l, int r, int idx) { - if (lazy[idx] != 0) { - seg[idx] += (r - l + 1) * lazy[idx]; - if (l != r) { - lazy[2 * idx] += lazy[idx]; - lazy[2 * idx + 1] += lazy[idx]; - } - lazy[idx] = 0; - } +void SegmentTreeLazy::updateRange(int l, int r, int val) { + updateRangeUtil(1, 0, size_ - 1, l, r, val); } -// Range update: add val to [ql, qr] -void update(int l, int r, int idx, int ql, int qr, int val) { - push(l, r, idx); +void SegmentTreeLazy::updateRangeUtil(int node, int start, int end, int l, int r, int val) { + if (lazy_[node] != 0) { + tree_[node] += (end - start + 1) * lazy_[node]; + if (start != end) { + lazy_[2 * node] += lazy_[node]; + lazy_[2 * node + 1] += lazy_[node]; + } + lazy_[node] = 0; + } - if (qr < l || ql > r) + if (start > end || start > r || end < l) { return; - if (ql <= l && r <= qr) { - lazy[idx] += val; - push(l, r, idx); + } + + if (start >= l && end <= r) { + tree_[node] += (end - start + 1) * val; + if (start != end) { + lazy_[2 * node] += val; + lazy_[2 * node + 1] += val; + } return; } - int mid = (l + r) / 2; - update(l, mid, 2 * idx, ql, qr, val); - update(mid + 1, r, 2 * idx + 1, ql, qr, val); - seg[idx] = seg[2 * idx] + seg[2 * idx + 1]; + int mid = (start + end) / 2; + updateRangeUtil(2 * node, start, mid, l, r, val); + updateRangeUtil(2 * node + 1, mid + 1, end, l, r, val); + tree_[node] = tree_[2 * node] + tree_[2 * node + 1]; } -// Range query: sum in [ql, qr] -int query(int l, int r, int idx, int ql, int qr) { - push(l, r, idx); +int SegmentTreeLazy::queryRange(int l, int r) { + return queryRangeUtil(1, 0, size_ - 1, l, r); +} - if (qr < l || ql > r) +int SegmentTreeLazy::queryRangeUtil(int node, int start, int end, int l, int r) { + if (start > end || start > r || end < l) { return 0; - if (ql <= l && r <= qr) - return seg[idx]; - - int mid = (l + r) / 2; - return query(l, mid, 2 * idx, ql, qr) + query(mid + 1, r, 2 * idx + 1, ql, qr); -} + } -int main() { - int n = 6; - int arr[] = {1, 3, 5, 7, 9, 11}; - for (int i = 0; i < n; ++i) - a[i] = arr[i]; + if (lazy_[node] != 0) { + tree_[node] += (end - start + 1) * lazy_[node]; + if (start != end) { + lazy_[2 * node] += lazy_[node]; + lazy_[2 * node + 1] += lazy_[node]; + } + lazy_[node] = 0; + } - build(0, n - 1, 1); + if (start >= l && end <= r) { + return tree_[node]; + } - cout << "Initial sum of [1, 3]: " << query(0, n - 1, 1, 1, 3) << endl; + int mid = (start + end) / 2; + int p1 = queryRangeUtil(2 * node, start, mid, l, r); + int p2 = queryRangeUtil(2 * node + 1, mid + 1, end, l, r); + return p1 + p2; +} - update(0, n - 1, 1, 1, 3, 10); // add 10 to range [1, 3] +int main() { + std::vector data{1, 3, 5, 7, 9, 11}; + SegmentTreeLazy st(data); - cout << "After range update, sum of [1, 3]: " << query(0, n - 1, 1, 1, 3) << endl; + std::cout << "Sum [1, 3]: " << st.queryRange(1, 3) << "\n"; + st.updateRange(1, 5, 10); + std::cout << "Sum [1, 3] after update: " << st.queryRange(1, 3) << "\n"; return 0; -} +} \ No newline at end of file diff --git a/code/data_structures/src/trie/trie.cpp b/code/data_structures/src/trie/trie.cpp index e27f198e7a..bc6f1c6eb4 100644 --- a/code/data_structures/src/trie/trie.cpp +++ b/code/data_structures/src/trie/trie.cpp @@ -1,68 +1,73 @@ -// trie.cpp -// Trie implementation in C++ +#include +#include +#include -#include -using namespace std; - -struct TrieNode { - TrieNode* children[26]; +class TrieNode { +public: + std::array children; bool isEnd; - TrieNode() { - isEnd = false; - fill(begin(children), end(children), nullptr); + TrieNode() : isEnd{false} { + children.fill(nullptr); } }; class Trie { public: - TrieNode* root; + Trie() : root_{new TrieNode()} { } - Trie() { - root = new TrieNode(); - } + void insert(const std::string& word); + bool search(const std::string& word); + bool startsWith(const std::string& prefix); - void insert(const string& word) { - TrieNode* node = root; - for (char ch : word) { - int i = ch - 'a'; - if (!node->children[i]) - node->children[i] = new TrieNode(); - node = node->children[i]; +private: + TrieNode* root_; +}; + +void Trie::insert(const std::string& word) { + TrieNode* node = root_; + for (char ch : word) { + int i = ch - 'a'; + if (!node->children[i]) { + node->children[i] = new TrieNode(); } - node->isEnd = true; + node = node->children[i]; } + node->isEnd = true; +} - bool search(const string& word) { - TrieNode* node = root; - for (char ch : word) { - int i = ch - 'a'; - if (!node->children[i]) - return false; - node = node->children[i]; +bool Trie::search(const std::string& word) { + TrieNode* node = root_; + for (char ch : word) { + int i = ch - 'a'; + if (!node->children[i]) { + return false; } - return node->isEnd; + node = node->children[i]; } + return node->isEnd; +} - bool startsWith(const string& prefix) { - TrieNode* node = root; - for (char ch : prefix) { - int i = ch - 'a'; - if (!node->children[i]) - return false; - node = node->children[i]; +bool Trie::startsWith(const std::string& prefix) { + TrieNode* node = root_; + for (char ch : prefix) { + int i = ch - 'a'; + if (!node->children[i]) { + return false; } - return true; + node = node->children[i]; } -}; + return true; +} int main() { Trie trie; trie.insert("apple"); - cout << "Search 'apple': " << trie.search("apple") << endl; // true - cout << "Search 'app': " << trie.search("app") << endl; // false - cout << "StartsWith 'app': " << trie.startsWith("app") << endl; // true + std::cout << "Search 'apple': " << trie.search("apple") << "\n"; + std::cout << "Search 'app': " << trie.search("app") << "\n"; + std::cout << "StartsWith 'app': " << trie.startsWith("app") << "\n"; trie.insert("app"); - cout << "Search 'app': " << trie.search("app") << endl; // true + std::cout << "Search 'app': " << trie.search("app") << "\n"; + return 0; } \ No newline at end of file From 96ce61c61829aee0509476711acebd8797e26570 Mon Sep 17 00:00:00 2001 From: Sreekar Reddy Date: Mon, 30 Jun 2025 01:44:45 +0530 Subject: [PATCH 3/3] Added formatted README files for Trie and Segment Tree --- .../src/segment_tree/README.md | 61 +++++++------------ code/data_structures/src/trie/README.md | 35 +++++------ 2 files changed, 37 insertions(+), 59 deletions(-) diff --git a/code/data_structures/src/segment_tree/README.md b/code/data_structures/src/segment_tree/README.md index cefe3db03b..aa4f257c52 100644 --- a/code/data_structures/src/segment_tree/README.md +++ b/code/data_structures/src/segment_tree/README.md @@ -1,51 +1,32 @@ # Segment Tree -A **Segment Tree** is a binary tree used for efficient range queries and updates on arrays. +A **Segment Tree** is a binary tree used for answering **range queries** (like sum, min, max) and performing **point or range updates** efficiently in logarithmic time. -This folder contains: -- Basic Segment Tree implementation -- Segment Tree with Lazy Propagation (for range updates) +## Variants ---- - -## Files - -| File | Description | -|----------------------------|---------------------------------------------------| -| `segment_tree.cpp` | Point updates and range sum queries | -| `segment_tree_lazy.cpp` | Supports range updates using lazy propagation | - ---- - -## Supported Operations - -### `segment_tree.cpp` -- Build from array -- Point update -- Range sum query - -### `segment_tree_lazy.cpp` -- Build from array -- **Range update** -- Range sum query with **lazy propagation** - ---- +- `segment_tree.cpp`: Basic segment tree supporting range sum queries and point updates. +- `segment_tree_lazy.cpp`: Segment tree with **lazy propagation** to support range updates efficiently. ## Time Complexity -| Operation | Time | -|------------------|------------| -| Build Tree | O(n) | -| Point Update | O(log n) | -| Range Query | O(log n) | -| Range Update | O(log n) *(with lazy)* | +| Operation | Basic Segment Tree | With Lazy Propagation | +|---------------|--------------------|------------------------| +| Build | O(N) | O(N) | +| Point Update | O(log N) | O(log N) | +| Range Query | O(log N) | O(log N) | +| Range Update | N/A | O(log N) | ---- +Where `N` is the size of the input array. -## Sample Usage (from `main()`) +## Sample Usage ```cpp -int arr[] = {1, 3, 5, 7, 9, 11}; -build(0, 5, 1); // Builds segment tree -cout << query(1, 3, 1); // Queries sum in range [1, 3] -update(1, 10, 1, 3, 0); // Range update in segment_tree_lazy.cpp +// Basic segment tree +SegmentTree st(data); +st.update(index, value); +st.query(left, right); + +// Segment tree with lazy propagation +SegmentTreeLazy st(data); +st.updateRange(left, right, delta); +st.queryRange(left, right); diff --git a/code/data_structures/src/trie/README.md b/code/data_structures/src/trie/README.md index c38128a4ca..4872e8b72f 100644 --- a/code/data_structures/src/trie/README.md +++ b/code/data_structures/src/trie/README.md @@ -1,33 +1,30 @@ -# Trie +# Trie (Prefix Tree) -A **Trie** is a tree-based data structure used to store a dynamic set of strings, where keys are usually strings over an alphabet. - ---- +A **Trie** is a tree-based data structure that stores a dynamic set or associative array where the keys are usually strings. It is efficient for **searching, inserting, and prefix queries**. ## Operations -- **Insert(string)** – Inserts a word into the Trie. -- **Search(string)** – Returns `true` if the word exists in the Trie. -- **StartsWith(prefix)** – Returns `true` if any word in the Trie starts with the given prefix. - ---- +- **Insert** a string into the Trie. +- **Search** to check if a string is present. +- **StartsWith** to check if a given prefix exists. ## Time Complexity -Let **L** be the length of the word/prefix: -- Insert: `O(L)` -- Search: `O(L)` -- Prefix check: `O(L)` +| Operation | Complexity | +|-------------|------------| +| Insert | O(L) | +| Search | O(L) | +| StartsWith | O(L) | ---- +Where `L` is the length of the string. -## Usage Example +## Sample Usage ```cpp Trie trie; trie.insert("apple"); -trie.search("apple"); // true -trie.search("app"); // false -trie.startsWith("app"); // true +trie.search("apple"); // returns true +trie.search("app"); // returns false +trie.startsWith("app"); // returns true trie.insert("app"); -trie.search("app"); // true +trie.search("app"); // returns true \ No newline at end of file