题解区似乎没有笛卡尔树写法?
考虑按 \(h_i\) 的大小建一棵笛卡尔树, \(h_i\) 越小离根越近。
树上的点 \(u\) 代表的是高为 \(h_u\) ,宽为 \(\sum\limits_{v\in \texttt{子树u}}w_v\) 的矩形,但是如果直接对每个点计算并求和会算重。
因此,对于每个点,我们只计算经过上边界 \(> h_{fa}\) 的矩形,这样就能做到不重不漏。
计算方式并不是这题的重点,略去。(绝对不是懒得写
\(\texttt{Code:}\)
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
template<typename T> inline void read(T &x) {
x = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
x = f ? -x : x;
}
template<typename T> inline void writeln(T x) {
if (x == 0) {putchar('0'); putchar('\n'); return;}
int w = 0, p[21];
while (x) p[++w] = x % 10, x /= 10;
while (w) putchar(p[w--] + '0');
putchar('\n');
}
const int cmd = 1e9 + 7;
const int N = 1e5 + 5;
int fpow(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = 1ll * a * a % cmd)
if (b & 1) res = 1ll * res * a % cmd;
return res;
}
int add(int a, int b) {a += b; return a < cmd ? a : a - cmd;}
int sub(int a, int b) {a -= b; return a < 0 ? a + cmd : a;}
int n, h[N], stk[N], top, ls[N], rs[N], ans, w[N], inv2 = fpow(2, cmd - 2);
void dfs(int u, int fa) {
if (ls[u]) dfs(ls[u], u), w[u] = add(w[u], w[ls[u]]);
if (rs[u]) dfs(rs[u], u), w[u] = add(w[u], w[rs[u]]);
int cur = 1ll * (h[u] + h[fa] + 1) * (h[u] - h[fa]) / 2 % cmd;
cur = 1ll * cur * (1 + w[u]) % cmd * w[u] % cmd * inv2 % cmd;
ans = add(ans, cur);
}
int main() {
#ifdef LOCAL
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
read(n);
for (int i = 1; i <= n; i++) read(h[i]);
for (int i = 1; i <= n; i++) read(w[i]);
for (int i = 1; i <= n; i++) {
while (top && h[stk[top]] > h[i]) ls[i] = stk[top--];
if (top) rs[stk[top]] = i;
stk[++top] = i;
}
dfs(stk[1], 0);
printf("%d", ans);
return 0;
}