小 C 的屏幕保护程序 / COCI 2012~2013 CONTEST #4 Task AKVARIJ 题解
前言
题意简述
给你一个长为
现在你要支持
- 查询:给定水位高度
,求水淹没的面积(不包括障碍)。 - 修改:给定
,将 。
题目分析
算法一:
发现
:
那么此时 一点水都没有,没有任何贡献。 :
增量为一个梯形,根据相似三角形,上底 ,下底 ,高 ,于是这部分面积为 ,令 。 :
增量即为一个 的正方形, 。
于是,我们可以在
算法二:
算法一菜飞了,但凡
我们很自然地发现,
- 对于
:
没有任何贡献。 - 对于
:
贡献为一个三角形,竖直边长 ,横边长 ,贡献为 。 - 对于
:
贡献贡献为一个梯形,拆分成一个三角形和一个矩形。 ,矩形面积为 ,总贡献为 。
读者已经猜到我想要表示什么了,这三种情况可以归约到关于
时间复杂度:
代码
算法一:
#include <cstdio> using namespace std; #define isdigit(x) ('0' <= x && x <= '9') inline void read(int &x) { x = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()); for (; isdigit(ch); ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48); } inline char read() { char ch; do ch = getchar(); while (ch != 'Q' && ch != 'U'); return ch; } inline int abs(int x) { return x < 0 ? -x : x; } inline int min(int a, int b) { return a < b ? a : b; } inline int max(int a, int b) { return a > b ? a : b; } const int N = 100010, V = 1010; using ld = long double; const ld eps = 1e-10; int n, m, h[N], mii[N], derr[N]; ld ans[V]; signed main() { read(n), read(m); for (int i = 1; i <= n; ++i) read(h[i]), mii[i - 1] = min(h[i], h[i - 1]), derr[i - 1] = abs(h[i] - h[i - 1]); for (int H = 1; H <= 1000; ++H) { ans[H] = ans[H - 1]; for (int i = 1, mi, der; i + 1 <= n; ++i) { mi = mii[i]; if (H <= mi) { } else if (H <= max(h[i], h[i + 1])) { der = derr[i]; ans[H] += (H - mi - 0.5) / der; } else { ans[H] += 1; } } } for (int H, p, v; m--; ) { char op = read(); if (op == 'Q') { read(H); #ifdef XuYueming printf(">>> "); #endif printf("%.1Lf\n", ans[H] + eps); } else { read(p), read(v), ++p; ld tot = 0; int mi = mii[p], der = derr[p]; int MI = mii[p - 1], DER = derr[p - 1]; for (int H = 1; H <= 1000; ++H) { if (p + 1 <= n) { if (H <= mi) { } else if (H <= max(h[p], h[p + 1])) { tot += (H - mi - 0.5) / der; } else { tot += 1; } } if (p - 1 >= 1) { if (H <= MI) { } else if (H <= max(h[p], h[p - 1])) { tot += (H - MI - 0.5) / DER; } else { tot += 1; } } ans[H] -= tot; } h[p] = v; tot = 0; mi = mii[p] = min(h[p], h[p + 1]); der = derr[p] = abs(h[p] - h[p + 1]); MI = mii[p - 1] = min(h[p - 1], h[p]); DER = derr[p - 1] = abs(h[p - 1] - h[p]); for (int H = 1; H <= 1000; ++H) { if (p + 1 <= n) { if (H <= mi) { } else if (H <= max(h[p], h[p + 1])) { tot += (H - mi - 0.5) / der; } else { tot += 1; } } if (p - 1 >= 1) { if (H <= MI) { } else if (H <= max(h[p], h[p - 1])) { tot += (H - MI - 0.5) / DER; } else { tot += 1; } } ans[H] += tot; } } } return 0; }
算法二:
#include <cstdio> #include <iostream> using namespace std; const int N = 100010; const int V = 1005; using ld = long double; int n, m, h[N]; struct Bit_Tree { ld tree[V]; inline void modify(int p, ld v) { for (; p < V; p += p & -p) tree[p] += v; } inline void modify(int l, int r, ld v) { modify(l, v), modify(r + 1, -v); } inline ld query(int p) { ld res = 0; for (; p; p &= p - 1) res += tree[p]; return res; } } t[3]; inline void add(int i, int f) { int mi = min(h[i], h[i + 1]); int mx = max(h[i], h[i + 1]); int delta = mx - mi; if (mi + 1 <= mx) { t[2].modify(mi + 1, mx, f * (.5 / delta)); t[1].modify(mi + 1, mx, f * (-1. * mi / delta)); t[0].modify(mi + 1, mx, f * (.5 * mi * mi / delta)); } t[1].modify(mx + 1, f * 1); t[0].modify(mx + 1, f * (delta / 2. - mx)); } inline ld query(int h) { return t[2].query(h) * h * h + t[1].query(h) * h + t[0].query(h); } signed main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", &h[i]); for (int i = 1; i < n; ++i) add(i, 1); for (int h0, p, v; m--; ) { char op[2]; scanf("%s", op); if (*op == 'Q') { scanf("%d", &h0); printf("%.1Lf\n", query(h0)); } else { scanf("%d%d", &p, &v), ++p; if (p > 1) add(p - 1, -1); if (p < n) add(p, -1); h[p] = v; if (p > 1) add(p - 1, 1); if (p < n) add(p, 1); } } return 0; }
卡常后代码
#include <cstdio> const int MAX = 1 << 26; char buf[MAX], *inp = buf; template <typename T> inline void read(T &x) { x = 0; char ch = *inp++; for (; ch < 48; ch = *inp++); for (; ch >= 48; ch = *inp++) x = (x << 3) + (x << 1) + (ch ^ 48); } const int N = 100010; const int V = 1005; using ld = long double; int n, m, h[N]; ld tree[V][3]; inline void add(int i, bool del) { int mi = h[i] < h[i + 1] ? h[i] : h[i + 1]; int mx = h[i] ^ h[i + 1] ^ mi; int delta = mx - mi; if (mi < mx) { int l = mi + 1, r = mx + 1; ld v2 = .5 / delta, v1 = -1. * mi / delta, v0 = mi * mi * v2; if (del) v0 = -v0, v1 = -v1, v2 = -v2; for (; l < r; l += l & -l) { tree[l][0] += v0; tree[l][1] += v1; tree[l][2] += v2; } for (; r < l && r < V; r += r & -r) { tree[r][0] -= v0; tree[r][1] -= v1; tree[r][2] -= v2; } for (; l < r; l += l & -l) { tree[l][0] += v0; tree[l][1] += v1; tree[l][2] += v2; } } ld v1 = 1, v0 = delta / 2. - mx; if (del) v1 = -v1, v0 = -v0; for (int p = mx + 1; p < V; p += p & -p) { tree[p][0] += v0; tree[p][1] += v1; } } inline ld query(int h) { ld v2 = 0, v1 = 0, v0 = 0; for (int p = h; p; p &= p - 1) { v0 += tree[p][0]; v1 += tree[p][1]; v2 += tree[p][2]; } return v2 * h * h + v1 * h + v0; } signed main() { fread(buf, 1, MAX, stdin), read(n), read(m), read(h[1]); for (int i = 2; i <= n; ++i) read(h[i]), add(i - 1, false); for (int h0, p, v; m--; ) { char op; do op = *inp++; while (op != 'Q' && op != 'U'); if (op == 'Q') { read(h0); printf("%.1Lf\n", query(h0)); } else { read(p), read(v), ++p; if (p > 1) add(p - 1, true); if (p < n) add(p, true); h[p] = v; if (p > 1) add(p - 1, false); if (p < n) add(p, false); } } return 0; }
本文作者:XuYueming,转载请注明原文链接:https://www.cnblogs.com/XuYueming/p/18705973。
若未作特殊说明,本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】