Skip to main content

pq/
lib.rs

1//! # PQ (aka Heap) :: Rusty
2
3use std::cmp::Reverse;
4use std::collections::{BTreeSet, BinaryHeap, HashMap};
5
6/// 407h Trapping Rain Water II
7struct Sol407;
8
9impl Sol407 {
10    pub fn trap_rain_water(height_map: Vec<Vec<i32>>) -> i32 {
11        let (rows, cols) = (height_map.len(), height_map[0].len());
12
13        #[derive(Debug, PartialEq, Eq, Ord, PartialOrd)]
14        struct Cell {
15            height: i32,
16            r: i32,
17            c: i32,
18        }
19
20        let mut visited = vec![vec![false; cols]; rows];
21
22        use std::cmp::Reverse;
23        use std::collections::BinaryHeap;
24
25        let mut pq = BinaryHeap::new();
26        for r in 0..rows {
27            for c in 0..cols {
28                if r == 0 || c == 0 || r == rows - 1 || c == cols - 1 {
29                    pq.push(Reverse(Cell {
30                        height: height_map[r][c],
31                        r: r as i32,
32                        c: c as i32,
33                    }));
34
35                    visited[r][c] = true;
36                }
37            }
38        }
39
40        println!(" -> {pq:?}");
41        println!(" -> {visited:?}");
42
43        let mut trap_water = 0;
44        let dirs = [-1, 0, 1, 0, -1];
45
46        while let Some(Reverse(cell)) = pq.pop() {
47            println!(" -> {cell:?}");
48
49            (0..4).for_each(|i| {
50                let (r, c) = (cell.r + dirs[i], cell.c + dirs[i + 1]);
51                if 0 <= r
52                    && r < rows as i32
53                    && 0 <= c
54                    && c < cols as i32
55                    && !visited[r as usize][c as usize]
56                {
57                    visited[r as usize][c as usize] = true;
58
59                    let h = height_map[r as usize][c as usize];
60                    if h < cell.height {
61                        trap_water += cell.height - h;
62                    }
63
64                    pq.push(Reverse(Cell {
65                        height: h.max(cell.height),
66                        r,
67                        c,
68                    }));
69                }
70            });
71        }
72
73        println!(" -> {visited:?}");
74
75        trap_water
76    }
77}
78
79/// 778 Swim in Rising Water
80struct Sol778 {}
81
82impl Sol778 {
83    pub fn swim_in_water(mut grid: Vec<Vec<i32>>) -> i32 {
84        use std::cmp::Reverse;
85        use std::collections::BinaryHeap;
86
87        let mut pq = BinaryHeap::new();
88        pq.push((Reverse(grid[0][0]), 0, 0));
89
90        let mut t = 0;
91        while let Some((Reverse(height), r, c)) = pq.pop() {
92            println!("-> {:?}", (height, r, c));
93
94            if r + 1 == grid.len() && c + 1 == grid[r].len() {
95                println!("-> {pq:?}");
96
97                return t.max(height);
98            }
99
100            t = t.max(height);
101
102            for (dr, dc) in [(1, 0), (-1, 0), (0, 1), (0, -1)] {
103                let (r, c) = (r.wrapping_add_signed(dr), c.wrapping_add_signed(dc));
104                if r < grid.len() && c < grid[r].len() && grid[r][c] != -1 {
105                    pq.push((Reverse(grid[r][c]), r, c));
106                    grid[r][c] = -1;
107                }
108            }
109        }
110
111        -1
112    }
113}
114
115/// 1046 Last Stone Weight
116struct Sol1046 {}
117
118impl Sol1046 {
119    pub fn last_stone_weight(stones: Vec<i32>) -> i32 {
120        use std::collections::BinaryHeap;
121
122        let mut hvs = BinaryHeap::new();
123        for stone in stones {
124            hvs.push(stone);
125        }
126
127        while hvs.len() > 1 {
128            let w1 = hvs.pop().unwrap();
129            let w2 = hvs.pop().unwrap();
130            if w1 > w2 {
131                hvs.push(w1 - w2);
132            }
133        }
134
135        hvs.pop().unwrap_or(0)
136    }
137}
138
139/// 1792m Maximum Average Pass Ratio
140struct Sol1792 {}
141
142impl Sol1792 {
143    pub fn max_average_ratio(classes: Vec<Vec<i32>>, extra_students: i32) -> f64 {
144        use std::cmp::Ordering;
145        use std::collections::BinaryHeap;
146
147        #[derive(Debug)]
148        struct Class {
149            gain: f64, // gain: (pass+1)/(total+1) - pass/total
150            pass: i32,
151            total: i32,
152        }
153
154        impl Ord for Class {
155            fn cmp(&self, other: &Self) -> Ordering {
156                self.gain.partial_cmp(&other.gain).unwrap()
157            }
158        }
159        impl PartialOrd for Class {
160            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
161                Some(self.cmp(other))
162            }
163        }
164
165        impl Eq for Class {}
166        impl PartialEq for Class {
167            fn eq(&self, other: &Self) -> bool {
168                self.pass == other.pass && self.total == other.total
169            }
170        }
171
172        fn gain(pass: i32, total: i32) -> f64 {
173            (pass + 1) as f64 / (total + 1) as f64 - pass as f64 / total as f64
174        }
175
176        let mut pq: BinaryHeap<Class> = classes
177            .iter()
178            .map(|v| (v[0], v[1]))
179            .map(|(pass, total)| Class {
180                gain: gain(pass, total),
181                pass,
182                total,
183            })
184            .collect();
185        println!("-> {pq:?}");
186
187        for _ in 0..extra_students {
188            if let Some(Class {
189                gain: _,
190                pass,
191                total,
192            }) = pq.pop()
193            {
194                pq.push(Class {
195                    gain: gain(pass + 1, total + 1),
196                    pass: pass + 1,
197                    total: total + 1,
198                });
199            }
200        }
201        println!("-> {pq:?}");
202
203        pq.iter()
204            .map(
205                |&Class {
206                     gain: _,
207                     pass,
208                     total,
209                 }| pass as f64 / total as f64,
210            )
211            .sum::<f64>()
212            / pq.len() as f64
213    }
214}
215
216/// 1912h Design Movie Rental System
217#[derive(Debug)]
218struct MovieRentingSystem1912 {
219    prices: std::collections::HashMap<(i32, i32), i32>, // (Shop, Movie) -> Price
220    movies: std::collections::HashMap<i32, std::collections::BTreeSet<(i32, i32)>>, // Movie -> (Price, Shop)
221    pq: std::collections::BTreeSet<(i32, i32, i32)>, // (Price, Shop, Movie)
222}
223
224impl MovieRentingSystem1912 {
225    /// 0 <= Shop < 3*10^5
226    /// 1 <= Movie, Price <= 10^4
227    #[allow(unused_variables)]
228    fn new(n: i32, entries: Vec<Vec<i32>>) -> Self {
229        MovieRentingSystem1912 {
230            prices: entries.iter().map(|v| ((v[0], v[1]), v[2])).collect(),
231            movies: entries.iter().map(|v| (v[0], v[1], v[2])).fold(
232                HashMap::new(),
233                |mut movies, (shop, movie, price)| {
234                    movies
235                        .entry(movie)
236                        .or_insert_with(BTreeSet::new)
237                        .insert((price, shop));
238
239                    movies
240                },
241            ),
242            pq: BTreeSet::new(),
243        }
244    }
245
246    fn search(&self, movie: i32) -> Vec<i32> {
247        self.movies.get(&movie).map_or(vec![], |movies| {
248            movies.iter().take(5).map(|&(_, shop)| shop).collect()
249        })
250    }
251
252    fn rent(&mut self, shop: i32, movie: i32) {
253        if let Some(&price) = self.prices.get(&(shop, movie)) {
254            self.movies
255                .get_mut(&movie)
256                .map(|movies| movies.remove(&(price, shop)));
257
258            self.pq.insert((price, shop, movie));
259        }
260    }
261
262    fn drop(&mut self, shop: i32, movie: i32) {
263        if let Some(&price) = self.prices.get(&(shop, movie)) {
264            self.movies
265                .get_mut(&movie)
266                .map(|movies| movies.insert((price, shop)));
267
268            self.pq.remove(&(price, shop, movie));
269        }
270    }
271
272    fn report(&self) -> Vec<Vec<i32>> {
273        self.pq
274            .iter()
275            .take(5)
276            .map(|&(_, shop, movie)| vec![shop, movie])
277            .collect()
278    }
279}
280
281/// 2231 Largest Number After Digit Swaps by Parity
282struct Sol2231 {}
283
284impl Sol2231 {
285    pub fn largest_integer(mut num: i32) -> i32 {
286        use std::collections::BinaryHeap;
287
288        let mut qs = [BinaryHeap::new(), BinaryHeap::new()];
289        let mut pars = vec![];
290
291        while num > 0 {
292            let parity = (num % 10) as usize & 1;
293
294            pars.push(parity);
295            qs[parity].push(num % 10);
296
297            num /= 10;
298        }
299        println!("-> {qs:?}");
300
301        let mut x = 0;
302        for &parity in pars.iter().rev() {
303            if let Some(digit) = qs[parity].pop() {
304                x = 10 * x + digit;
305            }
306        }
307
308        x
309    }
310}
311
312/// 2353m Design a Food Rating System
313#[derive(Debug)]
314struct FoodRatings2353 {
315    data: HashMap<String, BinaryHeap<(i32, Reverse<String>)>>,
316    f_cuisine: HashMap<String, String>,
317    f_rating: HashMap<String, i32>,
318}
319
320impl FoodRatings2353 {
321    fn new(foods: Vec<String>, cuisines: Vec<String>, ratings: Vec<i32>) -> Self {
322        FoodRatings2353 {
323            data: cuisines
324                .iter()
325                .enumerate()
326                .fold(HashMap::new(), |mut data, (i, cuisine)| {
327                    data.entry(cuisine.to_string())
328                        .and_modify(|pq| pq.push((ratings[i], Reverse(foods[i].clone()))))
329                        .or_insert(BinaryHeap::from([(ratings[i], Reverse(foods[i].clone()))]));
330
331                    data
332                }),
333            f_cuisine: foods
334                .iter()
335                .enumerate()
336                .map(|(i, food)| (food.clone(), cuisines[i].clone()))
337                .collect(),
338            f_rating: foods
339                .iter()
340                .zip(ratings.iter())
341                .map(|(food, &rating)| (food.clone(), rating))
342                .collect(),
343        }
344    }
345
346    fn change_rating(&mut self, food: String, new_rating: i32) {
347        if let Some(pq) = self.data.get_mut(&self.f_cuisine[&food]) {
348            pq.push((new_rating, Reverse(food.to_string())));
349            self.f_rating.insert(food.to_string(), new_rating);
350        }
351    }
352
353    fn highest_rated(&mut self, cuisine: String) -> String {
354        if let Some(pq) = self.data.get_mut(&cuisine) {
355            while let Some((rating, Reverse(food))) = pq.peek() {
356                if *rating == self.f_rating[food] {
357                    return food.clone();
358                } else {
359                    pq.pop(); // old "Rating", throw away!
360                }
361            }
362        }
363
364        panic!()
365    }
366}
367
368/// 3066m Minimum Operations to Exceed Threshold Value II
369struct Sol3066;
370
371impl Sol3066 {
372    pub fn min_operations(nums: Vec<i32>, k: i32) -> i32 {
373        use std::cmp::Reverse;
374        use std::collections::BinaryHeap;
375
376        let mut pq = BinaryHeap::new();
377        for n in nums {
378            pq.push(Reverse(n as usize));
379        }
380
381        let mut ops = 0;
382        while let Some(&Reverse(x)) = pq.peek() {
383            if x < k as usize {
384                pq.pop();
385                if let Some(Reverse(y)) = pq.pop() {
386                    pq.push(Reverse(x.min(y) * 2 + x.max(y)));
387                }
388            } else {
389                break;
390            }
391            ops += 1;
392        }
393
394        println!("-> {pq:?}");
395
396        ops
397    }
398}
399
400/// 3147m Taking Maximum Energy From the Mystic Dungeon
401struct Sol3147 {}
402
403impl Sol3147 {
404    pub fn maximum_energy(energy: Vec<i32>, k: i32) -> i32 {
405        (0..k as usize).fold(i32::MIN, |mut e_max, start| {
406            let mut e_sum = 0;
407            for e in energy.iter().skip(start).step_by(k as usize).rev() {
408                e_sum += e;
409                e_max = e_max.max(e_sum);
410            }
411
412            e_max
413        })
414    }
415}
416
417/// 3362m Zero Array Transformation III
418struct Sol3362;
419
420impl Sol3362 {
421    /// 1 <= N, Q <= 10^5
422    /// 0 <= N_ij <= 10^5
423    pub fn max_removal(nums: Vec<i32>, queries: Vec<Vec<i32>>) -> i32 {
424        use std::collections::BinaryHeap;
425
426        #[derive(Debug)]
427        struct Fenwick {
428            tree: Vec<i32>,
429        }
430
431        impl Fenwick {
432            fn new(size: usize) -> Self {
433                Fenwick {
434                    tree: vec![0; size + 1],
435                }
436            }
437
438            fn update(&mut self, mut i: usize, diff: i32) {
439                while i < self.tree.len() {
440                    self.tree[i] += diff;
441                    i += i & (!i + 1);
442                }
443            }
444
445            fn query(&self, mut i: usize) -> i32 {
446                let mut r = 0;
447                while i > 0 {
448                    r += self.tree[i];
449                    i -= i & (!i + 1);
450                }
451                r
452            }
453        }
454
455        let mut fwt = Fenwick::new(nums.len() + 2);
456        for query in &queries {
457            fwt.update(query[0] as usize + 1, 1);
458            fwt.update(query[1] as usize + 1 + 1, -1);
459        }
460        println!(
461            "-> {:?} {fwt:?}",
462            (1..=nums.len()).map(|i| fwt.query(i)).collect::<Vec<_>>()
463        );
464
465        let mut queries = queries;
466        queries.sort_by(|q1, q2| {
467            if q1[0] == q2[0] {
468                q2[1].cmp(&q1[1])
469            } else {
470                q1[0].cmp(&q2[0])
471            }
472        });
473        println!("-> {queries:?}");
474
475        let mut pq = BinaryHeap::new();
476
477        let (mut diff, mut diffs) = (0, vec![0; nums.len() + 1]);
478        let mut q = 0;
479        for (i, &n) in nums.iter().enumerate() {
480            diff += diffs[i];
481
482            while q < queries.len() && queries[q][0] as usize == i {
483                pq.push(queries[q][1]);
484                q += 1;
485            }
486
487            while diff < n {
488                match pq.peek() {
489                    Some(&right) if right >= i as i32 => {
490                        diff += 1;
491                        diffs[right as usize + 1] -= 1;
492
493                        pq.pop();
494                    }
495                    _ => break,
496                }
497            }
498
499            if diff < n {
500                return -1;
501            }
502        }
503
504        pq.len() as _
505    }
506}
507
508/// 3408m Design Task Manager
509#[derive(Debug)]
510struct TaskManager3408 {
511    oset: BTreeSet<(i32, i32, i32)>, // (Priority, Task, User)
512    task: HashMap<i32, (i32, i32)>,  // Task: -> (User, Priority)
513}
514
515impl TaskManager3408 {
516    fn new(tasks: Vec<Vec<i32>>) -> Self {
517        TaskManager3408 {
518            oset: tasks
519                .iter()
520                .map(|task| (task[2], task[1], task[0]))
521                .collect(),
522            task: tasks
523                .iter()
524                .map(|task| (task[1], (task[0], task[2])))
525                .collect(),
526        }
527    }
528
529    fn add(&mut self, user_id: i32, task_id: i32, priority: i32) {
530        self.oset.insert((priority, task_id, user_id));
531        self.task.insert(task_id, (user_id, priority));
532    }
533
534    fn edit(&mut self, task_id: i32, new_priority: i32) {
535        if let Some((user, priority)) = self.task.get_mut(&task_id)
536            && self.oset.take(&(*priority, task_id, *user)).is_some()
537        {
538            self.oset.insert((new_priority, task_id, *user));
539            *priority = new_priority;
540        }
541    }
542
543    fn rmv(&mut self, task_id: i32) {
544        if let Some((user, priority)) = self.task.remove(&task_id) {
545            self.oset.take(&(priority, task_id, user));
546        }
547    }
548
549    fn exec_top(&mut self) -> i32 {
550        if let Some((_, task, user)) = self.oset.pop_last() {
551            self.task.remove(&task);
552            return user;
553        }
554        -1
555    }
556}
557
558#[cfg(test)]
559mod tests;