結果
| 問題 |
No.2988 Min-Plus Convolution Query
|
| コンテスト | |
| ユーザー |
akakimidori
|
| 提出日時 | 2024-12-15 09:15:25 |
| 言語 | Rust (1.83.0 + proconio) |
| 結果 |
AC
|
| 実行時間 | 1,751 ms / 2,000 ms |
| コード長 | 5,793 bytes |
| コンパイル時間 | 13,416 ms |
| コンパイル使用メモリ | 380,996 KB |
| 実行使用メモリ | 23,244 KB |
| 最終ジャッジ日時 | 2024-12-15 09:16:23 |
| 合計ジャッジ時間 | 49,314 ms |
|
ジャッジサーバーID (参考情報) |
judge3 / judge4 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 40 |
ソースコード
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();
}
}
// N=|A|
// M=|B|
// 求値 O((logN)^2)
// 更新 O((logN)^2 logM)
pub struct MinPlusConvolutionPointUpdate<T> {
a: Vec<T>, // 変更する列
b: Vec<T>, // 下に凸
size: usize,
pos: Vec<usize>, // 左から右への切り替え地点
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 pos = vec![a.len() + b.len(); 2 * size];
let mut valid = vec![false; 2 * size];
for i in 0..n {
valid[size + i] = true;
}
let mut res = Self {
a,
b,
size,
pos,
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.pos[pos] <= 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 size = self.size;
let k = size.next_power_of_two().trailing_zeros()
- (v + 1).next_power_of_two().trailing_zeros();
let mut l = 2 * v;
let mut r = 2 * v + 1;
let x = (l << k) + (1 << k) - 1 - size;
let y = (r << k) - size;
let mut ng = y - 1;
let mut ok = x + self.b.len();
while ok - ng > 1 {
while l < size {
if self.pos[l] <= ng {
l = 2 * l + 1;
} else if ok <= self.pos[l] {
l = 2 * l;
} else {
break;
}
}
while r < size {
if self.pos[r] <= ng {
r = 2 * r + 1;
} else if ok <= self.pos[r] {
r = 2 * r;
} else {
break;
}
}
let mid = if l < size {
self.pos[l]
} else if r < size {
self.pos[r]
} else {
(ok + ng) / 2
};
if self.find_subtree(l, mid) >= self.find_subtree(r, mid) {
ok = mid;
} else {
ng = mid;
}
}
self.pos[v] = ok;
}
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