首先可以枚举一个位置的水量 \(w\),求 \(c_{w}\) 表示其方案数,答案为 \(\sum c_{w}\)。那么可以设 \(c_{i,j}\) 表示位置 \(i\) 水量 \(\ge j\) 的方案数,答案为 \(\sum c_{i,j}\)。一个位置 \(i\),墙高为 \(a_i\),要求其有至少 \(j\) 单位的水,那么左右的 \(\max h\) 必然都要 \(\ge a_i+j\)。考虑容斥,分别求出左边 \(\max h <a_{i}+j\),右边 \(\max h<a_{i}+j\) 和左右两边的 \(\max h<a_{i}+j\) 的方案数。
考虑一个位置对方案数的贡献,不妨设 \(a_{k}<b_{k},h=a_{i}+j\),若 \(h>b_{k}\),那么贡献为 \(\times 2\),若 \(a_k<h\le b_k\),那么贡献为 \(\times 1\),若 \(h\le a_k\),那么贡献为 \(\times 0\)。以单独求左边条件的方案数为例,我们从左到右扫描线,在维护时只需要维护后缀 \(\times 2\),记录前缀 \(\times 0\) 的最大限制即可,查询就查询后缀和。
对于两边都有限制的情况,每次就是消除 \(i\) 的限制。不妨先考虑所有限制,用线段树维护,扫描到 \(i\) 的时候撤销 \(i\) 的限制即可。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e5 + 5, M = 40, mod = 1e9 + 7, inf = 1e9;
inline void add(int & x, int y) {x += y; if (x >= mod) x -= mod;}
inline void dec(int & x, int y) {x += mod - y; if (x >= mod) x -= mod;}
inline int pls(int x, int y) {x += y; if (x >= mod) x -= mod; return x;}
inline int sub(int x, int y) {x += mod - y; if (x >= mod) x -= mod; return x;}
inline int mul(int x, int y) {return 1ll * x * y % mod;}
int n, a[N], b[N], ans, rt, _2[N], iv, pl[N], sl[N];
namespace smt {
int ls[N * M], rs[N * M], s[N * M], tag[N * M], cnt;
#define ls(p) ls[p]
#define rs(p) rs[p]
inline void init() {for (int i = 1; i <= cnt; ++i) ls[i] = rs[i] = s[i] = tag[i] = 0; cnt = rt = 0;}
inline int nnd(int len) {return cnt++, s[cnt] = len, tag[cnt] = 1, cnt;}
inline void work(int k, int p) {tag[p] = mul(tag[p], k), s[p] = mul(s[p], k);}
inline void psd(int l, int r, int p) {
int mid = (l + r) >> 1;
if (!ls(p)) ls(p) = nnd(mid - l + 1);
if (tag[p] ^ 1) work(tag[p], ls(p));
if (!rs(p)) rs(p) = nnd(r - mid);
if (tag[p] ^ 1) work(tag[p], rs(p));
tag[p] = 1;
}
inline void psu(int p) {s[p] = pls(s[ls(p)], s[rs(p)]);}
inline void ad(int l, int r, int L, int R, int k, int & p) {
if (L > R) return;
if (!p) p = nnd(r - l + 1);
if (l >= L && r <= R) return work(k, p);
int mid = (l + r) >> 1; psd(l, r, p);
if (L <= mid) ad(l, mid, L, R, k, ls(p));
if (R > mid) ad(mid + 1, r, L, R, k, rs(p));
psu(p);
}
inline int ask(int l, int r, int L, int R, int p) {
if (L > R) return 0;
if (!p) return max(0, min(r, R) - max(l, L) + 1);
if (l >= L && r <= R) return s[p];
int mid = (l + r) >> 1, ans = 0; psd(l, r, p);
if (L <= mid) add(ans, ask(l, mid, L, R, ls(p)));
if (R > mid) add(ans, ask(mid + 1, r, L, R, rs(p)));
return ans;
}
}
using namespace smt;
inline int qpow(int a, int b) {
int s = 1;
while (b) {
if (b & 1) s = mul(s, a);
a = mul(a, a), b >>= 1;
} return s;
}
signed main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i <= n; ++i) cin >> b[i];
_2[0] = 1; for (int i = 1; i <= n; ++i) _2[i] = mul(_2[i - 1], 2);
iv = qpow(2, mod - 2);
init();
for (int i = 1; i <= n; ++i) {
add(ans, mul(inf - a[i], qpow(2, n - 1)));
add(ans, mul(inf - b[i], qpow(2, n - 1)));
}
for (int i = 1, lm = 0; i <= n; ++i) {
int t = ask(1, inf, max(lm + 1, a[i] + 1), inf, rt);
dec(ans, mul(t, _2[n - i]));
t = ask(1, inf, max(lm + 1, b[i] + 1), inf, rt);
dec(ans, mul(t, _2[n - i]));
ad(1, inf, max(a[i], b[i]) + 1, inf, 2, rt), lm = max(lm, min(a[i], b[i]));
pl[i] = lm;
}
init();
for (int i = n, lm = 0; i; --i) {
int t = ask(1, inf, max(lm + 1, a[i] + 1), inf, rt);
dec(ans, mul(t, _2[i - 1]));
t = ask(1, inf, max(lm + 1, b[i] + 1), inf, rt);
dec(ans, mul(t, _2[i - 1]));
ad(1, inf, max(a[i], b[i]) + 1, inf, 2, rt), lm = max(lm, min(a[i], b[i]));
sl[i] = lm;
}
init();
for (int i = 1; i <= n; ++i) ad(1, inf, max(a[i], b[i]) + 1, inf, 2, rt);
for (int i = 1; i <= n; ++i) {
ad(1, inf, max(a[i], b[i]) + 1, inf, iv, rt);
add(ans, ask(1, inf, max(max(pl[i - 1], sl[i + 1]), a[i]) + 1, inf, rt));
add(ans, ask(1, inf, max(max(pl[i - 1], sl[i + 1]), b[i]) + 1, inf, rt));
ad(1, inf, max(a[i], b[i]) + 1, inf, 2, rt);
}
cout << ans << endl;
return 0;
}
标签:return,P10764,rs,Wall,2024,int,ls,inline,mod
From: https://www.cnblogs.com/Tagaki-san/p/18528879