我怎么这么菜。原题
考场做法是对 \(a\) 猫树分治,然后把 \(a_l, a_{l + 1}, \dots, a_r\) 在 \(b\) 中出现的数在 \(b\) 中的位置拎出来,做扫描线,用线段树求答案。
这个做法是 \(2\log\) 的,考虑如何优化。
事实上仔细观察后,发现分治和线段树都是无法避免的。
这里比较 Educational 了:考虑在 \(x\) 和 \(y\) 中找到带权中点,可以发现答案一定至少经过其中一个序列的带权中点,想一下容易证明正确性。
那么就可以将猫树分治的 \((l, r, mid)\) 改成 \([1, n]\) 以及带权中点,且总共只用做两次扫描线。
对于最优化问题(即使是 data structure 题),应该想到还能对决策范围进行 扩大 / 缩小,有时候会产生奇效。
点击查看代码
#include <bits/stdc++.h>
#define ll int
#define LL long long
#define pb push_back
#define pir pair <ll, ll>
#define mkp make_pair
#define fi first
#define se second
#define i128 __int128
using namespace std;
template <class T>
void rd(T &x) {char ch; bool f = 0;while(!isdigit(ch = getchar()))if(ch == '-') f = 1;x = ch - '0';while(isdigit(ch = getchar()))x = (x << 1) + (x << 3) + ch - '0';if(f) x = -x;
}
const ll maxn = 5e5 + 10, M = 1e6, inf = 1e9 + 5, mod = 1e9 + 7, iv = mod - mod / 2;
const LL INF = 1e18 + 5;
ll power(ll a, ll b = mod - 2, ll p = mod) {ll s = 1;while(b) {if(b & 1) s = 1ll * s * a % p;a = 1ll * a * a % p, b >>= 1;} return s;
}
template <class T1, class T2>
void add(T1 &x, const T2 y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T1, class T2>
void sub(T1 &x, const T2 y) { x = x < y? x + mod - y : x - y; }
template <class T1, class T2>
ll pls(const T1 x, const T2 y) { return x + y >= mod? x + y - mod : x + y; }
template <class T1, class T2>
ll mus(const T1 x, const T2 y) { return x < y? x + mod - y : x - y; }
template <class T1, class T2>
void chkmin(T1 &a, const T2 b) { a = a < b? a : b; }
template <class T1, class T2>
void chkmax(T1 &a, const T2 b) { a = a < b? b : a; }ll n, m, a[maxn], wa[maxn], b[maxn], wb[maxn];
ll posa[maxn << 1], posb[maxn << 1], h[maxn << 1], ht;
LL sa[maxn], sb[maxn];
struct ANSWER { LL w; ll l1, r1, l2, r2; void upd(LL a, ll b, ll c, ll d, ll e) {if(w < a) w = a, l1 = b, r1 = c, l2 = d, r2 = e; } } ans;ll L;
struct SGT {pair <LL, ll> mx[maxn << 2]; LL tag[maxn << 2];void addtag(ll p, LL v) { mx[p].fi += v, tag[p] += v; }void pushup(ll p) {mx[p] = max(mx[p << 1], mx[p << 1|1]);mx[p].fi += tag[p];}void modify(ll l, ll r, LL v) {addtag(l |= L, v);if((r |= L) ^ l) addtag(r, v);while(1) {ll x = l >> 1, y = r >> 1;if(x == y) break;if(l & 1 ^ 1) addtag(l ^ 1, v);if(r & 1) addtag(r ^ 1, v);pushup(l = x), pushup(r = y);}for(ll u = l >> 1; u; u >>= 1) pushup(u);}void build() {for(ll i = 1; i <= m; i++) mx[L | i] = mkp(-INF, i), tag[i] = 0;for(ll i = m + 1; i < L; i++) mx[L | i] = mkp(-INF, -INF), tag[i] = 0;mx[L] = mkp(-INF, -INF), tag[L] = 0;for(ll i = L - 1; i; i--) mx[i] = max(mx[i << 1], mx[i << 1|1]), tag[i] = 0;}
} tr;
ll stk1[maxn], top1, stk2[maxn], top2, ex1[maxn], ex2[maxn];
LL ep1[maxn], ep2[maxn];void push1(ll i, ll x, LL t) {while(top1 && ex1[top1] > x)tr.modify(stk1[top1 - 1] + 1, stk1[top1], t - ep1[top1]), --top1;stk1[++top1] = i, ep1[top1] = t, ex1[top1] = x;
}
void push2(ll i, ll x, LL t) {while(top2 && ex2[top2] < x)tr.modify(stk2[top2 - 1] + 1, stk2[top2], t - ep2[top2]), --top2;stk2[++top2] = i, ep2[top2] = t, ex2[top2] = x;
}void solve(ll z) {ll mid = 1;while(sa[n] >= 2 * sa[mid]) ++mid;L = 1, top1 = top2 = 0;while(L <= m) L <<= 1;tr.build();for(ll i = 1; i <= m; i++) {ll c = b[i]; LL w = 0;if(!posa[c]) push1(i, n, sa[n] - sa[mid]), push2(i, 1, sa[mid]), w = sa[n];else if(posa[c] > mid) {push1(i, posa[c] - 1, sa[posa[c] - 1] - sa[mid]);push2(i, 1, sa[mid]);w = sa[posa[c] - 1];} else {push1(i, n, sa[n] - sa[mid]);push2(i, posa[c] + 1, sa[mid] - sa[posa[c]]);w = sa[n] - sa[posa[c]];}tr.modify(i, i, w + INF - sb[i - 1]);auto tmp = tr.mx[1];ll pos1 = lower_bound(stk1 + 1, stk1 + 1 + top1, tmp.se) - stk1;ll pos2 = lower_bound(stk2 + 1, stk2 + 1 + top2, tmp.se) - stk2;if(!z) ans.upd(sb[i] + tmp.fi, ex2[pos2], ex1[pos1], tmp.se, i);else ans.upd(sb[i] + tmp.fi, tmp.se, i, ex2[pos2], ex1[pos1]);}
}int main() {rd(n), rd(m);for(ll i = 1; i <= n; i++) rd(a[i]), h[++ht] = a[i];for(ll i = 1; i <= n; i++) rd(wa[i]), sa[i] = sa[i - 1] + wa[i];for(ll i = 1; i <= m; i++) rd(b[i]), h[++ht] = b[i];for(ll i = 1; i <= m; i++) rd(wb[i]), sb[i] = sb[i - 1] + wb[i];sort(h + 1, h + 1 + ht);ht = unique(h + 1, h + 1 + ht) - h - 1;for(ll i = 1; i <= n; i++) {a[i] = lower_bound(h + 1, h + 1 + ht, a[i]) - h;posa[a[i]] = i;}for(ll i = 1; i <= m; i++) {b[i] = lower_bound(h + 1, h + 1 + ht, b[i]) - h;posb[b[i]] = i;}ans.upd(sa[n], 1, n, 0, 0), ans.upd(sb[m], 0, 0, 1, m);solve(0);for(ll i = 1; i <= ht; i++) swap(posa[i], posb[i]);swap(a, b), swap(n, m), swap(sa, sb), swap(wa, wb);solve(1);printf("%lld\n%d %d\n%d %d\n", ans.w, ans.l1, ans.r1, ans.l2, ans.r2);return 0;
}