use grove::*;
use itertools::Itertools;
use std::fs::{self, File};
use std::io::{BufRead, BufReader, Error, ErrorKind, Read};
use std::str::FromStr;
use std::time::Instant;
use example_data::{AddAction, SizedSummary};
use trees::avl::*;
use trees::splay::*;
use trees::treap::*;
type I = i32;
#[derive(PartialEq, Eq, Clone, Debug)]
struct Obstacle {
xlow: I,
xhigh: I,
ylow: I,
yhigh: I,
cost: I,
}
impl Obstacle {
fn edges(&self) -> (Edge, Edge) {
(
Edge {
is_opening: true,
xlow: self.xlow,
xhigh: self.xhigh,
y: self.ylow,
cost: self.cost,
},
Edge {
is_opening: false,
xlow: self.xlow,
xhigh: self.xhigh,
y: self.yhigh,
cost: self.cost,
},
)
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
struct Edge {
is_opening: bool,
xlow: I,
xhigh: I,
y: I,
cost: I,
}
impl Edge {
fn enlarge(&self, d: I) -> Edge {
Edge {
xlow: self.xlow - d,
y: if self.is_opening { self.y - d } else { self.y },
..*self
}
}
}
impl PartialOrd for Edge {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Edge {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.y
.cmp(&other.y)
.then((!self.is_opening).cmp(&!other.is_opening))
.then(self.xlow.cmp(&other.xlow))
.then(self.xhigh.cmp(&other.xhigh))
.then(self.cost.cmp(&other.cost))
}
}
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
struct Segment {
size: usize,
val: I,
}
impl Segment {
fn split_at_index(self, i: usize) -> (Segment, Segment) {
(
Segment {
size: i,
val: self.val,
},
Segment {
size: self.size - i,
val: self.val,
},
)
}
}
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
struct SizeMinSummary {
size: usize,
min: Option<I>,
}
impl std::ops::Add for SizeMinSummary {
type Output = Self;
fn add(self, other: Self) -> Self {
SizeMinSummary {
min: match (self.min, other.min) {
(Some(a), Some(b)) => Some(std::cmp::min(a, b)),
(Some(a), _) => Some(a),
(_, b) => b,
},
size: self.size + other.size,
}
}
}
impl std::default::Default for SizeMinSummary {
fn default() -> Self {
SizeMinSummary { size: 0, min: None }
}
}
impl SizedSummary for SizeMinSummary {
fn size(self) -> usize {
self.size
}
}
impl ToSummary<SizeMinSummary> for Segment {
fn to_summary(&self) -> SizeMinSummary {
SizeMinSummary {
size: self.size,
min: if self.size == 0 { None } else { Some(self.val) },
}
}
}
impl Acts<SizeMinSummary> for AddAction {
fn act_inplace(&self, summary: &mut SizeMinSummary) {
summary.min = summary.min.map(|max: I| max + self.add);
}
}
impl Acts<Segment> for AddAction {
fn act_inplace(&self, object: &mut Segment) {
object.val += self.add;
}
}
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
struct MyData {}
impl Data for MyData {
type Value = Segment;
type Summary = SizeMinSummary;
type Action = AddAction;
}
fn search_split<TR: ModifiableTreeRef<MyData>>(tree: TR, index: usize) {
let mut walker = tree.walker();
walker.search_subtree(index..index);
let left = walker.left_summary().size;
let v2option = walker.with_value(|val| {
let (v1, v2) = val.split_at_index(index - left);
*val = v1;
v2
});
if let Some(v2) = v2option {
walker.next_empty().unwrap(); walker.insert(v2).unwrap();
}
}
fn solve<T: SomeTree<MyData>>(m: usize, n: usize, budget: I, obstacles: Vec<Obstacle>) -> usize
where
for<'b> &'b mut T: ModifiableTreeRef<MyData>,
{
let (mut opening_edges, mut closing_edges): (Vec<Edge>, Vec<Edge>) =
obstacles.iter().map(|x| x.edges()).unzip();
opening_edges.sort_unstable();
closing_edges.sort_unstable();
let mut lo = 0;
let mut hi = std::cmp::min(n, m);
while hi > lo {
let k = (lo + hi + 1) / 2;
let mut tree: T = vec![Segment {
size: m + 1 - k,
val: 0,
}]
.into_iter()
.collect();
let event_iter = opening_edges
.iter()
.map(|e| e.enlarge((k - 1) as I))
.merge(closing_edges.iter().map(|e| e.enlarge((k - 1) as I)));
let mut prev_y = 0;
let mut possible: bool = false;
for edge in event_iter {
if edge.y > prev_y {
let temp_min = tree.subtree_summary().min.unwrap();
if temp_min <= budget {
possible = true;
break;
}
if edge.y >= n as I - k as I + 1 {
break;
}
prev_y = edge.y;
}
let xlow = std::cmp::max(edge.xlow, 0) as usize;
if edge.is_opening {
search_split(&mut tree, xlow);
search_split(&mut tree, edge.xhigh as usize);
}
tree.slice(xlow..edge.xhigh as usize).act(AddAction {
add: if edge.is_opening {
edge.cost
} else {
-edge.cost
},
});
}
let temp_min = tree.subtree_summary().min.unwrap();
if temp_min <= budget {
possible = true;
}
if possible {
lo = k;
} else {
hi = k - 1;
}
}
lo
}
fn run_from<R: Read, T: SomeTree<MyData>>(io: R) -> usize
where
for<'b> &'b mut T: ModifiableTreeRef<MyData>,
{
let br = BufReader::new(io);
let mut words_iter = br.lines().flat_map(|row| {
row.unwrap()
.split_whitespace()
.map(|x: &str| x.parse().unwrap())
.collect::<Vec<_>>()
});
let m = words_iter.next().unwrap();
let n = words_iter.next().unwrap();
let budget = words_iter.next().unwrap();
let p = words_iter.next().unwrap();
print!(" p={: <6}", p);
if p > 30_000 {
return 0;
}
std::io::Write::flush(&mut std::io::stdout()).unwrap();
let mut obstacles = vec![];
for _ in 0..p {
let e = "format not met";
let obstacle = Obstacle {
xlow: words_iter.next().expect(e) - 1,
ylow: words_iter.next().expect(e) - 1,
xhigh: words_iter.next().expect(e),
yhigh: words_iter.next().expect(e),
cost: words_iter.next().expect(e),
};
obstacles.push(obstacle);
}
let start = Instant::now();
let res = solve::<T>(m as usize, n as usize, budget, obstacles);
let duration = Instant::now().duration_since(start);
print!(" {: <12} ", format!("{:?}", duration));
res
}
fn run_on_file<T: SomeTree<MyData>>(name: &str) -> Result<(), Error>
where
for<'b> &'b mut T: ModifiableTreeRef<MyData>,
{
let current_dir = std::path::PathBuf::from_str("../grove/pyramid_base_test_files").unwrap();
print!("testing {: >8}.in:", name);
let mut file_path = current_dir.clone();
file_path.push(format!("{}.in", name));
std::io::Write::flush(&mut std::io::stdout())?;
let computed_res = run_from(File::open(file_path)?);
print!("{: >7}: ", computed_res);
let mut file_path = current_dir.clone();
file_path.push(format!("{}.out", name));
let mut content = String::from("");
File::open(file_path)?.read_to_string(&mut content)?;
let real_res: usize = content
.trim()
.parse()
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
if computed_res == real_res {
println!("Ok!");
} else {
println!("Failed!");
}
Ok(())
}
fn check_all_tests<T: SomeTree<MyData>>() -> Result<(), Error>
where
for<'b> &'b mut T: ModifiableTreeRef<MyData>,
{
let current_dir = std::path::PathBuf::from_str("../grove/pyramid_base_test_files").unwrap();
println!("Testing files from {:?}:", current_dir);
let filenames: Vec<String> = fs::read_dir(current_dir.clone())?
.filter_map(|entry| {
let entry = entry.unwrap();
let path = entry.path();
let (filename, filetype) = path.file_name()?.to_str()?.split_once('.')?;
if filetype == "in" {
Some(String::from(filename))
} else {
None
}
})
.sorted_by(|file1, file2| {
let num1: i32 = file1.trim_matches(char::is_alphabetic).parse().unwrap();
let num2: i32 = file2.trim_matches(char::is_alphabetic).parse().unwrap();
num1.cmp(&num2).then(file1.cmp(file2))
})
.collect();
let start = Instant::now();
for filename in filenames {
run_on_file(&filename)?;
}
let duration = Instant::now().duration_since(start);
println!("done all files: {: <16} overall", format!("{:?}", duration));
Ok(())
}
fn main() -> Result<(), Error> {
println!("starting treap\n");
check_all_tests::<Treap<_>>()?;
println!("done treap\n");
println!("starting splay\n");
check_all_tests::<SplayTree<_>>()?;
println!("done splay\n");
println!("starting avl\n");
check_all_tests::<AVLTree<_>>()?;
println!("done avl\n");
Ok(())
}