题解:CF671E Organizing a Race
分析
我们显然应该对于每个 \(l\) 求出其可匹配的最大 \(r\),但注意这个长度不是单调的(即若 \([l,r+1]\) 合法,区间 \([l,r]\) 不一定合法),所以不能二分。
我们可以先思考如何判断一个区间 \([l,r]\) 是否合法。显然可以贪心,\(l \rightarrow r\) 时在必须加油的时候再加,\(r \rightarrow l\) 时则全部加在 \(r\)。
推理
记:
-
\(sg_i=\sum_{j=1}^{i} g_j\)
-
\(sg'_i=\sum_{j=1}^{i} g_j+x_j\)(\(x_j\) 为在 \(j\) 城市放置的礼物个数)
-
\(sw_i=\sum_{j=1}^{i} w_j\)
-
\(c_1\) 为 \(l \rightarrow r\) 时要加的最小礼物数量,有 \(c_1=sg'_{r}-sg_{r}\)。
-
\(c_2\) 为 \(r \rightarrow l\) 时在 \(r\) 要加的最小礼物数量。根据回来时的要求可列出不等式:
那么显然 \(c_1+c_2 \le k\) 时区间是合法的,即:
设 \(A_i=sg'_i-sw_{i-1},B_i=sw_{i-1}-sg_i,C_i=sg'_{i-1}-sg_{i-1}\),那么区间 \([l,r]\) 合法的条件为:
求解
考虑一个区间 \([l,r]\) 在 \(l \rightarrow r\) 时会在什么时候加礼物。记 \(v_i=sg_{i-1}-sw_{i-1}\),根据贪心策略我们只会在 \(v_i>v_{i+1}\) 时在 \(i\) 加 \(val=v_i-v_{i+1}\) 个礼物,即 \(\forall j \in [i,n],A_j \leftarrow val,\forall j \in [i+1,n],C_i \leftarrow val\)。那么我们只需要将 \([l,n]\) 所有要加礼物的地方加礼物,然后按照 \(C_r \le k,B_r + \max_{i-l}^{r} A_i\le k\) 算答案即可,这个显然可以线段树二分。
我们考虑求出 \(nxt_i\) 表示从 \(i\) 出发,初始油量为 \(0\),下一个加礼物的地方(若不用加则 \(nxt_i=n+1\))。显然若按 \(i \rightarrow nxt_i\) 连边,我们就得到了一棵树,那么我们直接在树上 \(dfs\) 即可。具体地,进入一个点 \(x\) 时我们加上它的贡献,即 \(\forall i \in [nxt_x-1,n],A_i \leftarrow v_x-v_{nxt_{x}},\forall i \in [nxt_x,n],C_i \leftarrow v_x-v_{nxt_x}\),离开一个点时删除其贡献即可。
代码
#include <bits/stdc++.h>
#define ll long long
#define eb emplace_back
#define pii pair<int, ll>
#define mp make_pair
using namespace std;
const int maxn = 1e6 + 5;
int n, k, w[maxn], g[maxn], ans = 1;
ll sw[maxn], sg[maxn], v[maxn];
int nxt[maxn];
vector<int> e[maxn];
struct node {
ll a, b, c;
int ka;
node operator+ (const node &t) const {
if(ka == -1) return t;
node res;
if(a > t.a) res.a = a, res.ka = ka;
else res.a = t.a, res.ka = t.ka;
res.b = min(b, t.b), res.c = min(c, t.c);
return res;
}
};
struct SGT {
node tr[maxn << 2];
ll tagA[maxn << 2], tagC[maxn << 2];
inline int ls(int p) { return p << 1; }
inline int rs(int p) { return p << 1 | 1; }
inline void push_up(int p) { tr[p] = tr[ls(p)] + tr[rs(p)]; }
inline void changeA(int p, ll k) { tr[p].a += k; tagA[p] += k; }
inline void changeC(int p, ll k) { tr[p].c += k; tagC[p] += k; }
inline void push_down(int p) {
if(tagA[p]) {
changeA(ls(p), tagA[p]);
changeA(rs(p), tagA[p]);
tagA[p] = 0;
}
if(tagC[p]) {
changeC(ls(p), tagC[p]);
changeC(rs(p), tagC[p]);
tagC[p] = 0;
}
}
void build(int p, int l, int r) {
if(l == r) return (void)(tr[p] = {sg[l] - sw[l - 1], sw[l - 1] - sg[l], 0, l});
int mid = (l + r) >> 1;
build(ls(p), l, mid), build(rs(p), mid + 1, r);
push_up(p);
}
void updateA(int l, int r, int p, int pl, int pr, ll k) {
if(l <= pl && pr <= r) return changeA(p, k);
push_down(p);
int mid = (pl + pr) >> 1;
if(l <= mid) updateA(l, r, ls(p), pl, mid, k);
if(mid < r) updateA(l, r, rs(p), mid + 1, pr, k);
push_up(p);
}
void updateC(int l, int r, int p, int pl, int pr, ll k) {
if(l <= pl && pr <= r) return changeC(p, k);
push_down(p);
int mid = (pl + pr) >> 1;
if(l <= mid) updateC(l, r, ls(p), pl, mid, k);
if(mid < r) updateC(l, r, rs(p), mid + 1, pr, k);
push_up(p);
}
node qry(int l, int r, int p, int pl, int pr) {
if(l <= pl && pr <= r) return tr[p];
push_down(p);
int mid = (pl + pr) >> 1;
node res = {-1, -1, -1, -1};
if(l <= mid) res = res + qry(l, r, ls(p), pl, mid);
if(mid < r) res = res + qry(l, r, rs(p), mid + 1, pr);
return res;
}
int qryb(int l, int r, int p, int pl, int pr, ll v) {
if(r < pl || pr < l) return -1;
if(tr[p].b > v) return -1;
if(pl == pr) return pl;
push_down(p);
int mid = (pl + pr) >> 1;
if(tr[rs(p)].b <= v) {
int res = qryb(l, r, rs(p), mid + 1, pr, v);
if(~res) return res;
}
return qryb(l, r, ls(p), pl, mid, v);
}
int qryc(ll v, int p, int l, int r) {
if(l == r) return l;
push_down(p);
int mid = (l + r) >> 1;
if(tr[rs(p)].c <= v) return qryc(v, rs(p), mid + 1, r);
return qryc(v, ls(p), l, mid);
}
} sgt;
void dfs(int x) {
if(nxt[x] && nxt[x] <= n) {
ll val = v[x] - v[nxt[x]];
sgt.updateA(nxt[x] - 1, n, 1, 1, n, val);
sgt.updateC(nxt[x], n, 1, 1, n, val);
}
int r = sgt.qryc(k, 1, 1, n);
if(x < r) {
node A = sgt.qry(x, r - 1, 1, 1, n);
ans = max(ans, sgt.qryb(A.ka, r, 1, 1, n, k - A.a) - x + 1);
}
for(int y : e[x]) dfs(y);
if(nxt[x] && nxt[x] <= n) {
ll val = v[nxt[x]] - v[x];
sgt.updateA(nxt[x] - 1, n, 1, 1, n, val);
sgt.updateC(nxt[x], n, 1, 1, n, val);
}
}
int main() {
scanf("%d%d", &n, &k);
for(int i = 1; i < n; i++) {
scanf("%d", &w[i]);
sw[i] = sw[i - 1] + w[i];
}
for(int i = 1; i <= n; i++) {
scanf("%d", &g[i]);
sg[i] = sg[i - 1] + g[i];
}
stack<int> st;
for(int i = 1; i <= n; i++) {
v[i] = sg[i - 1] - sw[i - 1];
for(; !st.empty() && v[st.top()] > v[i]; st.pop()) nxt[st.top()] = i, e[i].eb(st.top());
st.push(i);
}
for(; !st.empty(); st.pop()) nxt[st.top()] = n + 1, e[n + 1].eb(st.top());
sgt.build(1, 1, n);
dfs(n + 1);
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号