結果
| 問題 |
No.2988 Min-Plus Convolution Query
|
| コンテスト | |
| ユーザー |
akakimidori
|
| 提出日時 | 2024-12-14 10:35:53 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 5,811 bytes |
| コンパイル時間 | 25,181 ms |
| コンパイル使用メモリ | 402,864 KB |
| 実行使用メモリ | 31,620 KB |
| 最終ジャッジ日時 | 2024-12-14 10:36:58 |
| 合計ジャッジ時間 | 50,448 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 17 WA * 15 TLE * 8 |
ソースコード
use std::io::Write;
fn main() {
input! {
n: usize,
q: usize,
a: [i32; n],
b: [i32; n],
ask: [(usize1, i32, usize); q],
}
let mut solver = MinPlusConvolutionPointUpdate::new(a, b);
let out = std::io::stdout();
let mut out = std::io::BufWriter::new(out.lock());
for (p, x, k) in ask {
solver.set(p, x);
writeln!(out, "{}", solver.find(k - 2)).ok();
}
}
pub struct MinPlusConvolutionPointUpdate<T> {
a: Vec<T>, // 変更する列
b: Vec<T>, // 下に凸
size: usize,
node: Vec<(usize, usize, usize)>, // L, R, Rの方が小さくなり始める場所
valid: Vec<bool>,
}
impl<T> MinPlusConvolutionPointUpdate<T>
where
T: std::ops::Add<Output = T> + Copy + Ord,
{
pub fn new(a: Vec<T>, b: Vec<T>) -> Self {
assert!(a.len() > 0 && b.len() > 0);
assert!(b.windows(3).all(|b| b[1] + b[1] <= b[0] + b[2]));
let n = a.len();
let size = n.next_power_of_two();
let mut node = vec![(n, n, 2 * n); 2 * size];
let mut valid = vec![false; 2 * size];
for (i, (node, valid)) in node[size..]
.iter_mut()
.zip(valid[size..].iter_mut())
.enumerate()
.take(a.len())
{
*node = (i, i, i);
*valid = true;
}
let mut res = Self {
a,
b,
size,
node,
valid,
};
for i in (1..size).rev() {
if res.valid[2 * i + 1] {
res.valid[i] = true;
res.pull(i);
}
}
res
}
pub fn set(&mut self, x: usize, v: T) {
assert!(x < self.a.len());
self.a[x] = v;
let mut pos = x + self.size;
pos /= 2;
while self.valid[pos] {
self.pull(pos);
pos /= 2;
}
}
pub fn find(&self, x: usize) -> T {
assert!(x < self.a.len() + self.b.len() - 1);
let mut l = x.saturating_sub(self.b.len() - 1) + self.size;
let mut r = x.min(self.a.len() - 1) + 1 + self.size;
let mut ans: Option<T> = None;
while l < r {
if l & 1 == 1 {
let v = self.find_subtree(l, x);
if ans.map_or(true, |p| p > v) {
ans = Some(v);
}
l += 1;
}
if r & 1 == 1 {
r -= 1;
let v = self.find_subtree(r, x);
if ans.map_or(true, |p| p > v) {
ans = Some(v);
}
}
l >>= 1;
r >>= 1;
}
ans.unwrap()
}
fn find_subtree(&self, v: usize, x: usize) -> T {
let mut pos = v;
while pos < self.size {
if self.node[pos].2 <= x {
pos = 2 * pos + 1;
} else {
pos = 2 * pos;
}
}
self.eval_at(pos - self.size, x)
}
fn pull(&mut self, v: usize) {
assert!(v < self.size);
let mut l = 2 * v;
let mut r = 2 * v + 1;
let size = self.size;
while l < size || r < size {
let p = self.node[l];
let q = self.node[r];
if p.0 != p.1 && self.eval(p.1, q.0, p.2) {
l = 2 * l;
} else if q.0 != q.1 && !self.eval(p.1, q.0, q.2) {
r = 2 * r + 1;
} else if p.0 != p.1 {
l = 2 * l + 1;
} else {
r = 2 * r;
}
}
let x = l - size;
let y = r - size;
let mut ng = x;
let mut ok = y + self.b.len();
while ok - ng > 1 {
let mid = (ok + ng) / 2;
if self.eval(x, y, mid) {
ok = mid;
} else {
ng = mid;
}
}
self.node[v] = (x, y, ok);
}
// A[x] + B[z-x] >= A[y] + B[z-y] かの判定
fn eval(&self, x: usize, y: usize, z: usize) -> bool {
assert!(x < y);
if z < y {
false
} else if z >= x + self.b.len() {
true
} else {
self.eval_at(x, z) >= self.eval_at(y, z)
}
}
fn eval_at(&self, x: usize, z: usize) -> T {
self.a[x] + self.b[z - x]
}
}
// ---------- begin input macro ----------
// reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
#[macro_export]
macro_rules! input {
(source = $s:expr, $($r:tt)*) => {
let mut iter = $s.split_whitespace();
input_inner!{iter, $($r)*}
};
($($r:tt)*) => {
let s = {
use std::io::Read;
let mut s = String::new();
std::io::stdin().read_to_string(&mut s).unwrap();
s
};
let mut iter = s.split_whitespace();
input_inner!{iter, $($r)*}
};
}
#[macro_export]
macro_rules! input_inner {
($iter:expr) => {};
($iter:expr, ) => {};
($iter:expr, $var:ident : $t:tt $($r:tt)*) => {
let $var = read_value!($iter, $t);
input_inner!{$iter $($r)*}
};
}
#[macro_export]
macro_rules! read_value {
($iter:expr, ( $($t:tt),* )) => {
( $(read_value!($iter, $t)),* )
};
($iter:expr, [ $t:tt ; $len:expr ]) => {
(0..$len).map(|_| read_value!($iter, $t)).collect::<Vec<_>>()
};
($iter:expr, chars) => {
read_value!($iter, String).chars().collect::<Vec<char>>()
};
($iter:expr, bytes) => {
read_value!($iter, String).bytes().collect::<Vec<u8>>()
};
($iter:expr, usize1) => {
read_value!($iter, usize) - 1
};
($iter:expr, $t:ty) => {
$iter.next().unwrap().parse::<$t>().expect("Parse error")
};
}
// ---------- end input macro ----------
akakimidori