2024.08 别急记录
1. ARC072F - Dam
发现当
点击查看代码
//AT_arc072_d #include <bits/stdc++.h> using namespace std; const int N = 1e6 + 10; int n, L, v[N]; double t[N]; typedef long long ll; pair<double, int> q[N]; int l = 1, r; int main(){ scanf("%d%d", &n, &L); for(int i = 1; i <= n; ++ i){ scanf("%lf%d", &t[i], &v[i]); } q[++r] = make_pair(t[1], v[1]); double sum = t[1] * 1.0 * v[1]; printf("%.9lf\n", sum / L); for(int i = 2; i <= n; ++ i){ int nw = v[i]; while(nw){ int mn = min(q[l].second, nw); sum -= q[l].first * mn; q[l].second -= mn; nw -= mn; if(!q[l].second){ ++ l; } } while(l <= r && q[r].first >= t[i]){ t[i] = (q[r].first * q[r].second + t[i] * v[i]) * 1.0 / (q[r].second + v[i]); v[i] += q[r].second; sum -= q[r].first * q[r].second; -- r; } q[++r] = make_pair(t[i], v[i]); sum += t[i] * 1.0 * v[i]; printf("%.9lf\n", sum / L); } return 0; }
2. ARC070E - NarrowRectangles
考虑设
写成 slope 的形式即为将斜率为
发现此时不方便求出
点击查看代码
//AT_arc070_c #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; int n, l[N], r[N], len[N]; typedef long long ll; priority_queue<ll> ql; priority_queue<ll, vector<ll>, greater<ll> > qr; ll tagl, tagr, ans; int main(){ scanf("%d", &n); for(int i = 1; i <= n; ++ i){ scanf("%d%d", &l[i], &r[i]); len[i] = r[i] - l[i]; if(i == 1){ ql.push(l[i]); qr.push(l[i]); ql.push(-1e18); qr.push(1e18); } else { tagl += len[i]; tagr += len[i-1]; if(l[i] < ql.top() - tagl){ ll x = ql.top() - tagl; ql.pop(); ans += x - l[i]; ql.push(l[i] + tagl); ql.push(l[i] + tagl); qr.push(x - tagr); } else if(l[i] <= qr.top() + tagr){ ql.push(l[i] + tagl); qr.push(l[i] - tagr); } else { ll x = qr.top() + tagr; qr.pop(); ans += l[i] - x; qr.push(l[i] - tagr); qr.push(l[i] - tagr); ql.push(x + tagl); } } } printf("%lld\n", ans); return 0; }
3. PA2021 - Poborcy podatkowi
考虑简单的
一个结论是随机
点击查看代码
//monkey #include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10, K = 1310; int n; vector<pair<int, int> > gr[N]; typedef long long ll; ll f[N][4], g[2][K+K+5][2]; void dfs(int x, int fa){ for(auto nd : gr[x]){ int y = nd.first, z = nd.second; if(y == fa) continue; dfs(y, x); } memset(g, 0xcf, sizeof(g)); g[0][K][0] = g[1][K][0] = 0; for(auto nd : gr[x]){ int y = nd.first, z = nd.second; if(y == fa) continue; for(int i = 0; i < K+K; ++ i){ for(int j = 0; j <= 1; ++ j){ if(g[0][i][j] < -1e13) continue; g[1][i][j^1] = max(g[1][i][j^1], g[0][i][j] + f[y][1] + z); g[1][i][j] = max(g[1][i][j], g[0][i][j] + f[y][3] + z); g[1][i][j] = max(g[1][i][j], g[0][i][j] + f[y][0]); if(i+1 < K+K){ g[1][i+1][j] = max(g[1][i+1][j], g[0][i][j] + f[y][0] + z); } if(i > 0){ g[1][i-1][j] = max(g[1][i-1][j], g[0][i][j] + f[y][2] + z); } } } memcpy(g[0], g[1], sizeof(g[1])); } f[x][0] = g[0][K][0]; f[x][1] = g[0][K+1][0]; f[x][2] = g[0][K][1]; f[x][3] = g[0][K-1][0]; } int main(){ srand(unsigned(time(NULL))); scanf("%d", &n); for(int i = 1; i < n; ++ i){ int u, v, w; scanf("%d%d%d", &u, &v, &w); gr[u].push_back(make_pair(v, w)); gr[v].push_back(make_pair(u, w)); } for(int i = 1; i <= n; ++ i){ int t = gr[i].size(); for(int j = 1; j <= t+t+t+t; ++ j){ int x = rand() % t, y = rand() % t; swap(gr[i][x], gr[i][y]); } } dfs(1, 0); printf("%lld\n", f[1][0]); return 0; }
4. YsOI2023 - 连通图计数
引理:一个
个节点,每个节点度数分别为 的有标号无根树的个数为 。
根据 prufer 数列,数列中
记
Sub 1.
此时构成一棵树,
Sub 2.
此时构成一棵基环树,对于环上点
Sub 3.
此时分两种情况:两个环有共边、两个环无共边。设
Sub 3A. 有共边
设这两个环交集为路径
所以环上点数仍然为
考虑先枚举
将两个环缩成一个方点,其它部分答案依旧为
Sub 3B. 无共边
此时两个环上点
枚举一个环上点数
但是此时两个方点之间可能有连边,需要把这种情况减掉。
有连边,就相当于构成了一个大小为
二者相减,得
同样要乘上环排列,得
对于每个
点击查看代码
// Problem: P9535 [YsOI2023] 连通图计数 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P9535 // Memory Limit: 512 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3e5 + 10; int n, m, a[N]; typedef long long ll; const ll P = 998244353; ll fac[N], inv[N], ans, sum; ll qp(ll x, ll y){ ll ans = 1; while(y){ if(y & 1){ ans = ans * x % P; } x = x * x % P; y >>= 1; } return ans; } int main(){ scanf("%d%d", &n, &m); fac[0] = 1; for(int i = 1; i <= n; ++ i){ scanf("%d", &a[i]); sum -= a[i]; fac[i] = fac[i-1] * i % P; } inv[n] = qp(fac[n], P-2); for(int i = n-1; i >= 0; -- i){ inv[i] = inv[i+1] * (i+1) % P; } if(m == n - 1){ ans = fac[n-2]; } else if(m == n){ ans = fac[n-1] * inv[2] % P; } else { sum += n+n; ll x = (n-sum) % P * qp(8, P-2) % P; ll y = (sum+2) % P * sum % P * qp(24, P-2) % P; ans = (x + y) * fac[n-1] % P * (sum-3) % P; } for(int i = 1; i <= n; ++ i){ ans = ans * inv[a[i]-1] % P; } printf("%lld\n", ans); return 0; }
5. AT_xmascon19_d - Sum of (-1)^f(n)
设
点击查看代码
//AT_xmascon19_d #include <bits/stdc++.h> using namespace std; const int N = 5e6 + 10; int p[N], v[N], c, f[N], B; typedef long long ll; ll n; map<ll, ll> vs, mp; ll dj(ll x){ if(x <= B){ return f[x]; } else if(vs[x] != 0){ return mp[x]; } else { vs[x] = 1; ll tmp = sqrt(x); for(ll l = 2, r; l <= x; l = r + 1){ r = x / (x / l); tmp -= dj(x / l) * (r - l + 1); } return mp[x] = tmp; } } int main(){ B = N - 10; f[1] = 1; for(int i = 2; i <= B; ++ i){ if(!v[i]){ p[++c] = i; f[i] = -1; } for(int j = 1; j <= c && p[j] * i <= B; ++ j){ v[i*p[j]] = 1; f[i*p[j]] = f[i] * f[p[j]]; if(i % p[j] == 0){ break; } } } for(int i = 2; i <= B; ++ i){ f[i] += f[i-1]; } scanf("%lld", &n); printf("%lld\n", dj(n)); return 0; }
6. LGP6329 - 【模板】点分树 | 震波
考虑点分治的过程中,将每次的重心连成一个树形结构,就形成了点分树。点分树有两个性质:
- 树高
。 - 对于
以及他们在点分树上的 lca ,有 在原树 路径上。
于是,对于与
所以对于这道题,我们维护两个数据结构
一些优化:
- dfs 序求 lca:https://www.luogu.com.cn/article/pu52m9ue。
- 使用树状数组代替线段树。观察到
的 范围为 ; 的 范围为 。( 为点分树内子树大小)。于是可以直接使用 vector 开树状数组。注意查询时处理查询下标 的情况。
证明:
- 点分树中
的子树是原树中一个包含 的连通块,自然 。 - 点分树中
的子树与 是原树中一个包含 的连通块与一个直接与此连通块相邻的点,自然 。
于是这么开树状数组是正确的。
点击查看代码
// Problem: P6329 【模板】点分树 | 震波 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P6329 // Memory Limit: 250 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; typedef long long ll; namespace FastIO { #if __cplusplus > 201700 #define INLINE_V inline #else #define INLINE_V #endif #if (defined(LOCAL) || defined(_WIN32)) && !defined(DISABLE_MMAP) #define DISABLE_MMAP #endif #ifndef DISABLE_MMAP #include <sys/mman.h> #endif INLINE_V constexpr int _READ_SIZE = 1 << 18; INLINE_V static char _read_buffer[_READ_SIZE], *_read_ptr = nullptr, *_read_ptr_end = nullptr; inline char gc() { if (__builtin_expect(_read_ptr == _read_ptr_end, false)) { _read_ptr = _read_buffer; _read_ptr_end = _read_buffer + fread(_read_buffer, 1, _READ_SIZE, stdin); if (__builtin_expect(_read_ptr == _read_ptr_end, false)) return EOF;} return *_read_ptr++; } INLINE_V constexpr int _WRITE_SIZE = 1 << 18; INLINE_V static char _write_buffer[_WRITE_SIZE], *_write_ptr = _write_buffer; inline void pc(char c) { *_write_ptr++ = c; if (__builtin_expect(_write_buffer + _WRITE_SIZE == _write_ptr, false)) { fwrite(_write_buffer, 1, _write_ptr - _write_buffer, stdout); _write_ptr = _write_buffer; } } INLINE_V struct _auto_flush { ~_auto_flush() { fwrite(_write_buffer, 1, _write_ptr - _write_buffer, stdout); } } _auto_flush; inline bool _isdigit(char c) { return (c & 16) && c != EOF; } inline bool _isgraph(char c) { return c > 32 && c != EOF; } template <class T> INLINE_V constexpr bool _is_integer = numeric_limits<T>::is_integer; template <class T> INLINE_V constexpr bool _is_signed = numeric_limits<T>::is_signed; template <class T> INLINE_V constexpr bool _is_unsigned = _is_integer<T> && !_is_signed<T>; template <> INLINE_V constexpr bool _is_integer<__int128> = true; template <> INLINE_V constexpr bool _is_integer<__uint128_t> = true; template <> INLINE_V constexpr bool _is_signed<__int128> = true; template <> INLINE_V constexpr bool _is_unsigned<__uint128_t> = true; inline void read(char &c) { do c = gc(); while (!_isgraph(c)); } inline void read_cstr(char *s) { char c = gc(); while (!_isgraph(c)) c = gc(); while (_isgraph(c)) *s++ = c, c = gc(); *s = 0; } inline void read(string &s) { char c = gc(); s.clear(); while (!_isgraph(c)) c = gc(); while (_isgraph(c)) s.push_back(c), c = gc(); } template <class T, enable_if_t<_is_signed<T>, int> = 0> inline void read(T &x) { char c = gc(); bool f = true; x = 0; while (!_isdigit(c)) { if (c == 45) f = false; c = gc(); } if (f) while (_isdigit(c)) x = x * 10 + (c & 15), c = gc(); else while (_isdigit(c)) x = x * 10 - (c & 15), c = gc(); } template <class T, enable_if_t<_is_unsigned<T>, int> = 0> inline void read(T &x) { char c = gc(); while (!_isdigit(c)) c = gc(); x = 0; while (_isdigit(c)) x = x * 10 + (c & 15), c = gc(); } inline void write(char c) { pc(c); } inline void write_cstr(const char *s) { while (*s) pc(*s++); } inline void write(const string &s) { for (char c : s) pc(c); } template <class T, enable_if_t<_is_signed<T>, int> = 0> inline void write(T x) { char buffer[numeric_limits<T>::digits10 + 1]; int digits = 0; if (x >= 0) do buffer[digits++] = (x % 10) | 48, x /= 10; while (x); else { pc(45); do buffer[digits++] = -(x % 10) | 48, x /= 10; while (x); } while (digits) pc(buffer[--digits]); } template <class T, enable_if_t<_is_unsigned<T>, int> = 0> inline void write(T x) { char buffer[numeric_limits<T>::digits10 + 1]; int digits = 0; do buffer[digits++] = (x % 10) | 48, x /= 10; while (x); while (digits) pc(buffer[--digits]); } template <int N> struct _tuple_io_helper { template <class... T> static inline void _read(tuple<T...> &x) { _tuple_io_helper<N - 1>::_read(x), read(get<N - 1>(x)); } template <class... T> static inline void _write(const tuple<T...> &x) { _tuple_io_helper<N - 1>::_write(x), pc(32), write(get<N - 1>(x)); } }; template <> struct _tuple_io_helper<1> { template <class... T> static inline void _read(tuple<T...> &x) { read(get<0>(x)); } template <class... T> static inline void _write(const tuple<T...> &x) { write(get<0>(x)); } }; template <class... T> inline void read(tuple<T...> &x) { _tuple_io_helper<sizeof...(T)>::_read(x); } template <class... T> inline void write(const tuple<T...> &x) { _tuple_io_helper<sizeof...(T)>::_write(x); } template <class T1, class T2> inline void read(pair<T1, T2> &x) { read(x.first), read(x.second); } template <class T1, class T2> inline void write(const pair<T1, T2> &x) { write(x.first), pc(32), write(x.second); } template <class T1, class... T2> inline void read(T1 &x, T2 &...y) { read(x), read(y...); } template <class... T> inline void read_cstr(char *x, T *...y) { read_cstr(x), read_cstr(y...); } template <class T1, class... T2> inline void write(const T1 &x, const T2 &...y) { write(x), write(y...); } template <class... T> inline void write_cstr(const char *x, const T *...y) { write_cstr(x), write_cstr(y...); } template <class T> inline void print(const T &x) { write(x); } inline void print_cstr(const char *x) { write_cstr(x); } template <class T1, class... T2> inline void print(const T1 &x, const T2 &...y) { print(x), pc(32), print(y...); } template <class... T> inline void print_cstr(const char *x, const T *...y) { print_cstr(x), pc(32), print_cstr(y...); } inline void println() { pc(10); } inline void println_cstr() { pc(10); } template <class... T> inline void println(const T &...x) { print(x...), pc(10); } template <class... T> inline void printk(const T &...x) { print(x...), pc(32); } template <class... T> inline void println_cstr(const T *...x) { print_cstr(x...), pc(10); } } using namespace FastIO; const int N = 1e5 + 10; int n, m, a[N], la, fat[N], ban[N], rt, siz[N]; int dep[N], anc[N][20]; vector<int> g[N]; int tmp, mn = 1e9; void csiz(int x, int fa){ siz[x] = 1; for(int i : g[x]){ if(!ban[i] && i != fa){ csiz(i, x); siz[x] += siz[i]; } } } void fndc(int x, int fa, int sum){ for(int i : g[x]){ if(!ban[i] && i != fa){ fndc(i, x, sum); } } int mx = sum - siz[x]; for(int i : g[x]){ if(!ban[i] && i != fa){ mx = max(mx, siz[i]); } } if(mx < mn){ tmp = x; mn = mx; } } int build(int x){ csiz(x, 0); mn = 1e9; fndc(x, 0, siz[x]); int c = tmp; siz[c] = siz[x]; ban[c] = 1; for(int i : g[c]){ if(!ban[i]){ int xx; fat[xx = build(i)] = c; } } return c; } int dn, dfn[N], mi[19][N]; int get(int x, int y) {return dfn[x] < dfn[y] ? x : y;} void dfs(int id, int f) { mi[0][dfn[id] = ++dn] = f; dep[id] = dep[f] + 1; for(int it : g[id]) if(it != f) dfs(it, id); } int lca(int u, int v) { if(u == v) return u; if((u = dfn[u]) > (v = dfn[v])) swap(u, v); int d = __lg(v - u++); return get(mi[d][u], mi[d][v - (1 << d) + 1]); } int dis(int x, int y){ int l = lca(x, y); return dep[x] + dep[y] - dep[l] * 2; } struct bit{ int siz; vector<int> bit; void init(int l){ siz = l; bit.resize(siz+3); for(int i = 0; i < siz+3; ++ i){ bit[i] = 0; } } void add(int x, int v){ ++ x; while(x <= siz){ bit[x] += v; x += x & -x; } } int ask(int x){ int rs = 0; if(x < 0){ return 0; } x = min(x + 1, siz); while(x){ rs += bit[x]; x -= x & -x; } return rs; } } c[2][N]; void add(int x, int val){ int nw = x; while(true){ c[0][nw].add(dis(x, nw), val); if(nw != rt){ c[1][nw].add(dis(x, fat[nw]), val); } else { break; } nw = fat[nw]; } } int main(){ read(n, m); for(int i = 1; i <= n; ++ i){ read(a[i]); } for(int i = 1; i < n; ++ i){ int u, v; read(u, v); g[u].push_back(v); g[v].push_back(u); } dfs(1, 0); for(int i = 1; i <= __lg(n); i++) for(int j = 1; j + (1 << i) - 1 <= n; j++) mi[i][j] = get(mi[i - 1][j], mi[i - 1][j + (1 << i - 1)]); rt = build(1); for(int i = 1; i <= n; ++ i){ c[0][i].init(siz[i]); c[1][i].init(siz[i] + 1); } for(int i = 1; i <= n; ++ i){ add(i, a[i]); } while(m --){ int op, x, y; read(op, x, y); x ^= la; y ^= la; if(op == 0){ int nw = x, ls, ans = 0; while(true){ ans += c[0][nw].ask(y - dis(x, nw)); if(nw != x){ ans -= c[1][ls].ask(y - dis(x, nw)); } if(nw == rt){ break; } ls = nw; nw = fat[nw]; } la = ans; println(ans); } else { add(x, y - a[x]); a[x] = y; } } return 0; }
7. WC2021 - 括号路径
观察到若
点击查看代码
//qoj1301 #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3e5 + 10; int n, m, k, fa[N], siz[N]; vector<pair<int, int> > g[N]; map<int, int> mp[N]; queue<pair<int, int> > q; long long ans; int gf(int x){ return x == fa[x] ? x : fa[x] = gf(fa[x]); } void merge(int x, int y){ x = gf(x); y = gf(y); if(x == y){ return; } if(siz[x] < siz[y]){ swap(x, y); } fa[y] = x; siz[x] += siz[y]; for(auto [i, j] : mp[y]){ if(mp[x][i]){ q.push(make_pair(mp[x][i], j)); } else { mp[x][i] = j; } } } int main(){ scanf("%d%d%d", &n, &m, &k); for(int i = 1; i <= m; ++ i){ int u, v, w; scanf("%d%d%d", &u, &v, &w); if(!mp[v][w]){ mp[v][w] = u; } else { q.push(make_pair(u, mp[v][w])); } } for(int i = 1; i <= n; ++ i){ fa[i] = i; siz[i] = 1; } while(!q.empty()){ int x, y; tie(x, y) = q.front(); q.pop(); merge(x, y); } for(int i = 1; i <= n; ++ i){ if(fa[i] == i){ ans += 1ll * siz[i] * (siz[i]-1) / 2; } } printf("%lld\n", ans); return 0; }
8. LuoguP6326 - Shopping
首先不妨连通块包含根。那么显然有一个
- 若不选
,则 的子树全部不能选,更新到 ; - 若选
,强制选一个 后更新到 。
使用单调队列优化多重背包即可做到
点击查看代码
// Problem: P6326 Shopping // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P6326 // Memory Limit: 125 MB // Time Limit: 1500 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 510, M = 4010; int n, m, w[N], c[N], d[N]; vector<int> g[N]; int siz[N], ban[N], tmp, mn, cnt, dfn[N]; int f[N][M], h[2][M], ans, q[M]; void pr(int x, int fa){ dfn[++cnt] = x; siz[x] = 1; for(int i : g[x]){ if(i != fa && !ban[i]){ pr(i, x); siz[x] += siz[i]; } } } void ks(int p){ for(int y = 0; y < c[p]; ++ y){ int l = 1, r = 0; for(int x = 0; x * c[p] + y <= m; ++ x){ while(l <= r && q[l] < x - d[p] + 1){ ++ l; } while(l <= r && h[0][q[r]*c[p]+y] - q[r]*w[p] < h[0][x*c[p]+y] - x*w[p]){ -- r; } q[++r] = x; h[1][x*c[p]+y] = h[0][q[l]*c[p]+y] - q[l]*w[p]+x*w[p]; } } } void dp(int rt){ for(int i = 0; i <= siz[rt] + 1; ++ i){ memset(f[i], 0xcf, sizeof(f[i])); } f[1][0] = 0; for(int p = 1; p <= siz[rt]; ++ p){ int x = dfn[p]; for(int i = 0; i <= m; ++ i){ f[p+siz[x]][i] = max(f[p+siz[x]][i], f[p][i]); } for(int j = m; j >= 0; -- j){ if(j < c[x]){ h[0][j] = -1e9; } else { h[0][j] = f[p][j-c[x]] + w[x]; } } ks(x); for(int j = 0; j <= m; ++ j){ f[p+1][j] = max(f[p+1][j], h[1][j]); ans = max(ans, h[1][j]); } } } void cs(int x, int fa){ siz[x] = 1; for(int i : g[x]){ if(!ban[i] && i != fa){ cs(i, x); siz[x] += siz[i]; } } } void fc(int x, int fa, int sum){ for(int i : g[x]){ if(!ban[i] && i != fa){ fc(i, x, sum); } } int mx = sum - siz[x]; for(int i : g[x]){ if(!ban[i] && i != fa){ mx = max(mx, siz[i]); } } if(mx < mn){ tmp = x; mn = mx; } } void cl(int x){ cs(x, 0); mn = 1e9; fc(x, 0, siz[x]); int c = tmp; cnt = 0; pr(c, 0); dp(c); ban[c] = 1; for(int i : g[c]){ if(!ban[i]){ cl(i); } } } int main(){ int T = 1; scanf("%d", &T); while(T--){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++ i) scanf("%d", &w[i]); for(int i = 1; i <= n; ++ i) scanf("%d", &c[i]); for(int i = 1; i <= n; ++ i) scanf("%d", &d[i]); for(int i = 1; i < n; ++ i){ int u, v; scanf("%d%d", &u, &v); g[u].push_back(v); g[v].push_back(u); } cl(1); printf("%d\n", ans); for(int i = 1; i <= n; ++ i){ ban[i] = siz[i] = 0; vector<int> ().swap(g[i]); } ans = 0; } return 0; }
9. LuoguP8476 -「GLR-R3」惊蛰
考虑设
- 将
的部分全体 ; - 将
的部分全体 再加上下标; - 取后缀 min,即二分出
内 的部分修改为 。
发现都可以线段树维护。每个节点维护推平、加、加下标三个 tag 再加一个区间
但是这题如果直接动态开点空间应该过不去,所以可以先离散化(这样加下标的部分变为加
点击查看代码
// Problem: GLR-R3 - 惊蛰 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P8476 // Memory Limit: 512 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e6 + 10; int n, C, a[N], b[N], tot = 1; struct node{ ll ad, mx, sp; int ls, rs, l, r, tg; } t[N*12]; void psd(int p){ int mid = t[p].l + t[p].r >> 1; if(!t[p].ls && t[p].l != t[p].r){ t[p].ls = ++ tot; t[t[p].ls].l = t[p].l; t[t[p].ls].r = mid; } if(!t[p].rs && t[p].l != t[p].r){ t[p].rs = ++ tot; t[t[p].rs].l = mid + 1; t[t[p].rs].r = t[p].r; } if(t[p].sp != -1){ t[t[p].ls].mx = t[t[p].rs].mx = t[p].sp; t[t[p].ls].tg = t[t[p].ls].ad = 0; t[t[p].ls].sp = t[p].sp; t[t[p].rs].tg = t[t[p].rs].ad = 0; t[t[p].rs].sp = t[p].sp; t[p].sp = -1; } t[t[p].ls].tg += t[p].tg; t[t[p].ls].mx += (ll)t[p].tg * b[t[t[p].ls].r]; t[t[p].rs].tg += t[p].tg; t[t[p].rs].mx += (ll)t[p].tg * b[t[t[p].rs].r]; t[p].tg = 0; t[t[p].ls].ad += t[p].ad; t[t[p].ls].mx += t[p].ad; t[t[p].rs].ad += t[p].ad; t[t[p].rs].mx += t[p].ad; t[p].ad = 0; } void psu(int p){ t[p].mx = max(t[t[p].ls].mx, t[t[p].rs].mx); } void add(int p, int l, int r, int ql, int qr, ll v){ if(qr < l || r < ql) return; if(ql <= l && r <= qr){ t[p].mx += v; t[p].ad += v; } else { int mid = l + r >> 1; psd(p); add(t[p].ls, l, mid, ql, qr, v); add(t[p].rs, mid+1, r, ql, qr, v); psu(p); } } void tag(int p, int l, int r, int ql, int qr){ if(qr < l || r < ql) return; if(ql <= l && r <= qr){ t[p].mx += b[t[p].r]; ++ t[p].tg; } else { int mid = l + r >> 1; psd(p); tag(t[p].ls, l, mid, ql, qr); tag(t[p].rs, mid+1, r, ql, qr); psu(p); } } void mdf(int p, int l, int r, int ql, int qr, ll v){ if(qr < l || r < ql) return; if(ql <= l && r <= qr){ t[p].mx = t[p].sp = v; t[p].tg = t[p].ad = 0; } else { int mid = l + r >> 1; psd(p); mdf(t[p].ls, l, mid, ql, qr, v); mdf(t[p].rs, mid+1, r, ql, qr, v); psu(p); } } ll qry(int p, int l, int r, int x){ if(l == r){ return t[p].mx; } else { int mid = l + r >> 1; psd(p); if(x <= mid) return qry(t[p].ls, l, mid, x); else return qry(t[p].rs, mid+1, r, x); } } int fnd(int p, int l, int r, int ql, int qr, ll v){ if(l == r){ return l; } else { int mid = l + r >> 1; psd(p); if(t[t[p].ls].mx >= v){ return fnd(t[p].ls, l, mid, ql, qr, v); } else { return fnd(t[p].rs, mid+1, r, ql, qr, v); } } } int main(){ scanf("%d%d", &n, &C); if(!C){ puts("0"); return 0; } bool flg = 1; for(int i = 1; i <= n; ++ i){ scanf("%d", &a[i]); if(a[i] < a[i-1]){ flg = 0; } b[i] = a[i]; } if(flg){ ll sum = 0, ans = 8e18; for(int i = 1; i <= n; ++ i){ sum += a[i]; ans = min(ans, a[i] * (ll)i - sum + ((ll)n-i) * C); } printf("%lld\n", ans); return 0; } sort(b + 1, b + n + 1); int mx = unique(b + 1, b + n + 1) - b - 1; t[1].l = 1, t[1].r = mx; for(int i = 1; i <= n; ++ i){ a[i] = lower_bound(b + 1, b + mx + 1, a[i]) - b; add(1, 1, mx, 1, mx, C); add(1, 1, mx, a[i], mx, -b[a[i]]-C); tag(1, 1, mx, a[i], mx); ll val = qry(1, 1, mx, a[i]); int p = fnd(1, 1, mx, 1, a[i]-1, val); mdf(1, 1, mx, p, a[i]-1, val); } printf("%lld\n", qry(1, 1, mx, 1)); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步