#[allow(non_snake_case)] // day iにジュエルをx個残したときの最大利益は区分線形凸関数になる // 遷移は 傾きA_i,長さB_iの線分と傾きC_i,長さD_iの線分を挿入してから // 前から長さD_i削り、後ろからB_i削るかんじになる // 最小値削除,最大値削除,追加が高速にできればいい // BinaryHeapを2つ使って管理 fn main(){ use proconio::*; input!{ t:usize, } use itertools::*; use std::cmp::Reverse as Rev; use std::collections::BinaryHeap as Heap; let solve=||{ input!{ n:usize, K:i64, A:[i64;n], B:[i64;n], C:[i64;n], D:[i64;n], } let mut len=vec![K]; let mut minQ=Heap::from([(Rev(1e9 as i64),0)]); let mut maxQ=Heap::from([(1e9 as i64,0)]); let mut Z=0; // 定数項 for (a,b,c,d) in izip!(A,B,C,D){ minQ.push((Rev(a),len.len())); maxQ.push((a,len.len())); len.push(b); minQ.push((Rev(c),len.len())); maxQ.push((c,len.len())); len.push(d); Z-=c*d; // 後ろからb削る let mut rem=b; while rem!=0{ let &(_,id)=maxQ.peek().unwrap(); let sub=rem.min(len[id]); rem-=sub; len[id]-=sub; if len[id]==0{ maxQ.pop().unwrap(); } } // 前からd削る let mut rem=d; while rem!=0{ let &(Rev(coeff),id)=minQ.peek().unwrap(); let sub=rem.min(len[id]); rem-=sub; len[id]-=sub; if len[id]==0{ minQ.pop().unwrap(); } Z+=coeff*sub; } } print!("{}\n",-Z); }; for _ in 0..t{ solve(); } }