版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89923841
【题目链接】
【思路要点】
- 考虑一次钻孔操作对全局水位的影响。
- 注意到一次钻孔操作只会使得水向某一方向流动,以下认为水向右流动进行讨论。
- 定义函数 表示区间 的水位和。
- 定义函数 表示假设区间 两侧的挡板高度无限,在区间中没有水的时候需要在 处倒入多少水使得 处的水位到达 。
- 定义操作 表示假设区间 两侧的挡板高度无限,抽空区间中的水,并在 处倒入一定量的水,直到 处的水位到达 。
- 假设一次钻孔操作 使得 处的水将要流向 。
- 首先,找到最小的 ,使得 内的水位相等,且挡板高度均不足水位高度。
- 计算 ,即最多可以流出的水量,并执行操作 。
- 其次,找到最大的 ,使得 ,即此次流动将会影响到的区间右端点。
- 最后,找到最大的 ,使得 ,即最后 处的水位,执行操作 即可。
- 使用李超式线段树可以在 的时间内实现 中的每一个功能,直接二分找到 可以得到 的时间复杂度。
- 将二分改为在线段树上二分,时间复杂度降为 。
【代码】
// Long Double Version Till Line 439 #include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const long double eps = 1e-12; typedef long long ll; typedef long double ld; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc, l, r, len, tagtype; // 0 : Nothing, 1 : FloodLeft, 2 : FloodRight ld Sum, Max, Min, Maxh, WaterL, WaterR, Tag, VolLeft, VolRight; } a[MAXN * 2]; ld water[MAXN], block[MAXN]; int root, size, n; ld res, cur; bool vis; ld getvolLeft(int root, ld cur) { if (a[root].len == 1) return cur; if (cur > max(a[a[root].rc].Maxh, block[a[a[root].lc].r])) return cur * a[a[root].rc].len + getvolLeft(a[root].lc, cur); else return a[root].VolLeft + getvolLeft(a[root].rc, cur); } ld getvolRight(int root, ld cur) { if (a[root].len == 1) return cur; if (cur > max(a[a[root].lc].Maxh, block[a[a[root].lc].r])) return cur * a[a[root].lc].len + getvolRight(a[root].rc, cur); else return a[root].VolRight + getvolRight(a[root].lc, cur); } void update(int root, bool type) { a[root].Sum = a[a[root].lc].Sum + a[a[root].rc].Sum; a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max); a[root].Min = min(a[a[root].lc].Min, a[a[root].rc].Min); a[root].WaterL = a[a[root].lc].WaterL; a[root].WaterR = a[a[root].rc].WaterR; if (type) { a[root].Maxh = max(a[a[root].lc].Maxh, a[a[root].rc].Maxh); chkmax(a[root].Maxh, block[a[a[root].lc].r]); a[root].VolLeft = getvolLeft(a[root].lc, max(a[a[root].rc].Maxh, block[a[a[root].lc].r])); a[root].VolRight = getvolRight(a[root].rc, max(a[a[root].lc].Maxh, block[a[a[root].lc].r])); } } void puttag(int root, ld tag, int type) { a[root].Tag = tag; a[root].tagtype = type; a[root].Min = tag; a[root].Max = max(tag, a[root].Maxh); if (type == 1) { a[root].WaterR = tag; a[root].WaterL = max(tag, a[root].Maxh); a[root].Sum = getvolLeft(root, tag); } else { a[root].WaterL = tag; a[root].WaterR = max(tag, a[root].Maxh); a[root].Sum = getvolRight(root, tag); } } void pushdown(int root) { if (a[root].tagtype == 1) { puttag(a[root].rc, a[root].Tag, 1); puttag(a[root].lc, max(a[root].Tag, max(a[a[root].rc].Maxh, block[a[a[root].lc].r])), 1); a[root].tagtype = 0; } if (a[root].tagtype == 2) { puttag(a[root].lc, a[root].Tag, 2); puttag(a[root].rc, max(a[root].Tag, max(a[a[root].lc].Maxh, block[a[a[root].lc].r])), 2); a[root].tagtype = 0; } } void build(int &root, int l, int r) { root = ++size; a[root].l = l; a[root].r = r; a[root].len = r - l + 1; if (l == r) { a[root].Sum = water[l]; a[root].Max = water[l]; a[root].Min = water[l]; a[root].WaterL = water[l]; a[root].WaterR = water[l]; a[root].Maxh = 0; return; } int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); update(root, true); } void init(int x) { n = x; root = size = 0; for (int i = 1; i <= n; i++) scanf("%Lf", &water[i]); for (int i = 1; i <= n - 1; i++) scanf("%Lf", &block[i]); build(root, 1, n); } ld querySum(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].Sum; pushdown(root); int mid = (l + r) / 2; ld ans = 0; if (mid >= ql) ans += querySum(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) ans += querySum(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); return ans; } ld querySum(int l, int r) { return querySum(root, 1, n, l, r); } void modifyLeft(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { puttag(root, cur, 1); chkmax(cur, max(a[root].Maxh, block[a[root].l - 1])); return; } pushdown(root); int mid = (l + r) / 2; if (mid + 1 <= qr) modifyLeft(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); if (mid >= ql) modifyLeft(a[root].lc, l, mid, ql, min(mid, qr)); update(root, false); } void modifyLeft(int l, int r, ld tag) { cur = tag, modifyLeft(root, 1, n, l, r); } void modifyRight(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { puttag(root, cur, 2); chkmax(cur, max(a[root].Maxh, block[a[root].r])); return; } pushdown(root); int mid = (l + r) / 2; if (mid >= ql) modifyRight(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) modifyRight(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); update(root, false); } void modifyRight(int l, int r, ld tag) { cur = tag, modifyRight(root, 1, n, l, r); } void queryLeft(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { res += getvolLeft(root, cur); chkmax(cur, max(a[root].Maxh, block[a[root].l - 1])); return; } pushdown(root); int mid = (l + r) / 2; if (mid + 1 <= qr) queryLeft(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); if (mid >= ql) queryLeft(a[root].lc, l, mid, ql, min(mid, qr)); } ld queryLeft(int l, int r, ld val) { cur = val, res = 0; queryLeft(root, 1, n, l, r); return res; } void queryRight(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { res += getvolRight(root, cur); chkmax(cur, max(a[root].Maxh, block[a[root].r])); return; } pushdown(root); int mid = (l + r) / 2; if (mid >= ql) queryRight(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) queryRight(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); } ld queryRight(int l, int r, ld val) { cur = val, res = 0; queryRight(root, 1, n, l, r); return res; } void modifyBlock(int root, int l, int r, int pos, ld val) { int mid = (l + r) / 2; pushdown(root); if (mid > pos) modifyBlock(a[root].lc, l, mid, pos, val); if (mid + 1 <= pos) modifyBlock(a[root].rc, mid + 1, r, pos, val); block[pos] = val; update(root, true); } void modifyBlock(int pos, ld val) { if (val > block[pos] - eps) return; modifyBlock(root, 1, n, pos, val); } int findLeft(int root, int l, int r, int pos, ld val) { if (l == r) { if (fabs(a[root].Max - val) <= eps && fabs(a[root].Min - val) <= eps && block[l] <= val - eps) return l; else return l + 1; } pushdown(root); int mid = (l + r) / 2; if (r <= pos) { if (fabs(a[root].Max - val) <= eps && fabs(a[root].Min - val) <= eps && block[r] <= val - eps && a[root].Maxh <= val - eps) return l; if (fabs(a[a[root].rc].Max - val) <= eps && fabs(a[a[root].rc].Min - val) <= eps && block[r] <= val - eps && a[a[root].rc].Maxh <= val - eps) return findLeft(a[root].lc, l, mid, pos, val); else return findLeft(a[root].rc, mid + 1, r, pos, val); } if (mid + 1 <= pos) { int tmp = findLeft(a[root].rc, mid + 1, r, pos, val); if (tmp != mid + 1) return tmp; } return findLeft(a[root].lc, l, mid, pos, val); } int findLeft(int pos, ld val) { if (pos == 0) return 1; else return findLeft(root, 1, n, pos, val); } int findRight(int root, int l, int r, int pos, ld val) { if (l == r) { if (fabs(a[root].Max - val) <= eps && fabs(a[root].Min - val) <= eps && block[l - 1] <= val - eps) return l; else return l - 1; } pushdown(root); int mid = (l + r) / 2; if (l >= pos) { if (fabs(a[root].Max - val) <= eps && fabs(a[root].Min - val) <= eps && block[l - 1] <= val - eps && a[root].Maxh <= val - eps) return r; if (fabs(a[a[root].lc].Max - val) <= eps && fabs(a[a[root].lc].Min - val) <= eps && block[l - 1] <= val - eps && a[a[root].lc].Maxh <= val - eps) return findRight(a[root].rc, mid + 1, r, pos, val); else return findRight(a[root].lc, l, mid, pos, val); } if (mid >= pos) { int tmp = findRight(a[root].lc, l, mid, pos, val); if (tmp != mid) return tmp; } return findRight(a[root].rc, mid + 1, r, pos, val); } int findRight(int pos, ld val) { if (pos == n + 1) return n; else return findRight(root, 1, n, pos, val); } void addToRight(int root) { size++; a[size].l = a[size - 1].l; a[size].r = a[root].r; a[size].len = a[size - 1].len + a[root].len; a[size].lc = size - 1; a[size].rc = root; update(size, true); } void addToLeft(int root) { size++; a[size].l = a[root].l; a[size].r = a[size - 1].r; a[size].len = a[root].len + a[size - 1].len; a[size].lc = root; a[size].rc = size - 1; update(size, true); } void Extract(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { if (vis) addToRight(root); else { vis = true; a[++size] = a[root]; } return; } int mid = (l + r) / 2; if (mid >= ql) Extract(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) Extract(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); } int findRightmost(int root, int l, int r, int pos, ld vol) { if (l == r) { addToRight(root); if (getvolLeft(size, a[size].WaterR) - a[size].Sum <= vol + eps) return l; else { size--; return l - 1; } } pushdown(root); int mid = (l + r) / 2; if (l >= pos) { addToRight(root); if (getvolLeft(size, a[size].WaterR) - a[size].Sum <= vol + eps) return r; size--; addToRight(a[root].lc); if (getvolLeft(size, a[size].WaterR) - a[size].Sum <= vol + eps) return findRightmost(a[root].rc, mid + 1, r, pos, vol); else { size--; return findRightmost(a[root].lc, l, mid, pos, vol); } } if (mid >= pos) { int tmp = findRightmost(a[root].lc, l, mid, pos, vol); if (tmp != mid) return tmp; } return findRightmost(a[root].rc, mid + 1, r, pos, vol); } int findRightmost(int ql, int qr, ld vol) { int oldsize = size; vis = false, Extract(root, 1, n, ql, qr); int ans = findRightmost(root, 1, n, qr + 1, vol); size = oldsize; return ans; } int findLeftmost(int root, int l, int r, int pos, ld vol) { if (l == r) { addToLeft(root); if (getvolRight(size, a[size].WaterL) - a[size].Sum <= vol + eps) return l; else { size--; return l + 1; } } pushdown(root); int mid = (l + r) / 2; if (r <= pos) { addToLeft(root); if (getvolRight(size, a[size].WaterL) - a[size].Sum <= vol + eps) return l; size--; addToLeft(a[root].rc); if (getvolRight(size, a[size].WaterL) - a[size].Sum <= vol + eps) return findLeftmost(a[root].lc, l, mid, pos, vol); else { size--; return findLeftmost(a[root].rc, mid + 1, r, pos, vol); } } if (mid + 1 <= pos) { int tmp = findLeftmost(a[root].rc, mid + 1, r, pos, vol); if (tmp != mid + 1) return tmp; } return findLeftmost(a[root].lc, l, mid, pos, vol); } int findLeftmost(int ql, int qr, ld vol) { int oldsize = size; vis = false, Extract(root, 1, n, ql, qr); int ans = findLeftmost(root, 1, n, ql - 1, vol); size = oldsize; return ans; } int floodLeft(int root, int l, int r, int ql, int qr, ld vol) { if (r < ql) return r + 1; if (l == r) { cur += a[root].Sum; if (a[root].WaterL * (qr - l + 1) - cur <= vol + eps) return l; else { cur -= a[root].Sum; return l + 1; } } pushdown(root); int mid = (l + r) / 2; if (l >= ql && r <= qr) { cur += a[root].Sum; if (a[root].WaterL * (qr - l + 1) - cur <= vol + eps) return l; cur += a[a[root].rc].Sum - a[root].Sum; if (a[a[root].rc].WaterL * (qr - a[a[root].rc].l + 1) - cur <= vol + eps) return floodLeft(a[root].lc, l, mid, ql, qr, vol); else { cur -= a[a[root].rc].Sum; return floodLeft(a[root].rc, mid + 1, r, ql, qr, vol); } } if (mid + 1 <= qr) { int tmp = floodLeft(a[root].rc, mid + 1, r, ql, qr, vol); if (tmp != mid + 1) return tmp; } return floodLeft(a[root].lc, l, mid, ql, qr, vol); } void floodLeft(int ql, int qr, ld vol) { ld tmp = querySum(qr, qr); vol -= queryLeft(ql, qr, tmp) - querySum(ql, qr); modifyLeft(ql, qr, tmp); cur = 0; int pos = floodLeft(root, 1, n, ql, qr, vol); modifyLeft(ql, qr, (vol + querySum(pos, qr)) / (qr - pos + 1)); } int floodRight(int root, int l, int r, int ql, int qr, ld vol) { if (l > qr) return l - 1; if (l == r) { cur += a[root].Sum; if (a[root].WaterR * (l - ql + 1) - cur <= vol + eps) return l; else { cur -= a[root].Sum; return l - 1; } } pushdown(root); int mid = (l + r) / 2; if (l >= ql && r <= qr) { cur += a[root].Sum; if (a[root].WaterR * (r - ql + 1) - cur <= vol + eps) return r; cur += a[a[root].lc].Sum - a[root].Sum; if (a[a[root].lc].WaterR * (a[a[root].lc].r - ql + 1) - cur <= vol + eps) return floodRight(a[root].rc, mid + 1, r, ql, qr, vol); else { cur -= a[a[root].lc].Sum; return floodRight(a[root].lc, l, mid, ql, qr, vol); } } if (ql <= mid) { int tmp = floodRight(a[root].lc, l, mid, ql, qr, vol); if (tmp != mid) return tmp; } return floodRight(a[root].rc, mid + 1, r, ql, qr, vol); } void floodRight(int ql, int qr, ld vol) { ld tmp = querySum(ql, ql); vol -= queryRight(ql, qr, tmp) - querySum(ql, qr); modifyRight(ql, qr, tmp); cur = 0; int pos = floodRight(root, 1, n, ql, qr, vol); modifyRight(ql, qr, (vol + querySum(ql, pos)) / (pos - ql + 1)); } } ST; int main() { int n, q; read(n), read(q); ST.init(n); for (int i = 1; i <= q; i++) { int opt, pos; read(opt), read(pos); if (opt == 2) { printf("%.8Lf\n", ST.querySum(pos, pos)); continue; } ld h; scanf("%Lf", &h); ST.modifyBlock(pos, h); ld pre = ST.querySum(pos, pos), suf = ST.querySum(pos + 1, pos + 1); if (pre > suf + eps && pre > ST.block[pos] + eps) { int l = ST.findLeft(pos - 1, pre); ld vol = ST.querySum(l, pos) - ST.queryLeft(l, pos, h); ST.modifyLeft(l, pos, h); int r = ST.findRightmost(l, pos, vol); ST.floodLeft(l, r, vol); } else if (suf > pre + eps && suf > ST.block[pos] + eps) { int r = ST.findRight(pos + 2, suf); ld vol = ST.querySum(pos + 1, r) - ST.queryRight(pos + 1, r, h); ST.modifyRight(pos + 1, r, h); int l = ST.findLeftmost(pos + 1, r, vol); ST.floodRight(l, r, vol); } } for (int i = 1; i <= n; i++) printf("%.8Lf ", ST.querySum(i, i)); return 0; } // Double Version Till Line 878 #include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const double eps = 1e-12; typedef long long ll; typedef double ld; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc, l, r, len, tagtype; // 0 : Nothing, 1 : FloodLeft, 2 : FloodRight ld Sum, Max, Min, Maxh, WaterL, WaterR, Tag, VolLeft, VolRight; } a[MAXN * 2]; ld water[MAXN], block[MAXN]; int root, size, n; ld res, cur; bool vis; ld getvolLeft(int root, ld cur) { if (a[root].len == 1) return cur; if (cur > max(a[a[root].rc].Maxh, block[a[a[root].lc].r])) return cur * a[a[root].rc].len + getvolLeft(a[root].lc, cur); else return a[root].VolLeft + getvolLeft(a[root].rc, cur); } ld getvolRight(int root, ld cur) { if (a[root].len == 1) return cur; if (cur > max(a[a[root].lc].Maxh, block[a[a[root].lc].r])) return cur * a[a[root].lc].len + getvolRight(a[root].rc, cur); else return a[root].VolRight + getvolRight(a[root].lc, cur); } void update(int root, bool type) { a[root].Sum = a[a[root].lc].Sum + a[a[root].rc].Sum; a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max); a[root].Min = min(a[a[root].lc].Min, a[a[root].rc].Min); a[root].WaterL = a[a[root].lc].WaterL; a[root].WaterR = a[a[root].rc].WaterR; if (type) { a[root].Maxh = max(a[a[root].lc].Maxh, a[a[root].rc].Maxh); chkmax(a[root].Maxh, block[a[a[root].lc].r]); a[root].VolLeft = getvolLeft(a[root].lc, max(a[a[root].rc].Maxh, block[a[a[root].lc].r])); a[root].VolRight = getvolRight(a[root].rc, max(a[a[root].lc].Maxh, block[a[a[root].lc].r])); } } void puttag(int root, ld tag, int type) { a[root].Tag = tag; a[root].tagtype = type; a[root].Min = tag; a[root].Max = max(tag, a[root].Maxh); if (type == 1) { a[root].WaterR = tag; a[root].WaterL = max(tag, a[root].Maxh); a[root].Sum = getvolLeft(root, tag); } else { a[root].WaterL = tag; a[root].WaterR = max(tag, a[root].Maxh); a[root].Sum = getvolRight(root, tag); } } void pushdown(int root) { if (a[root].tagtype == 1) { puttag(a[root].rc, a[root].Tag, 1); puttag(a[root].lc, max(a[root].Tag, max(a[a[root].rc].Maxh, block[a[a[root].lc].r])), 1); a[root].tagtype = 0; } if (a[root].tagtype == 2) { puttag(a[root].lc, a[root].Tag, 2); puttag(a[root].rc, max(a[root].Tag, max(a[a[root].lc].Maxh, block[a[a[root].lc].r])), 2); a[root].tagtype = 0; } } void build(int &root, int l, int r) { root = ++size; a[root].l = l; a[root].r = r; a[root].len = r - l + 1; if (l == r) { a[root].Sum = water[l]; a[root].Max = water[l]; a[root].Min = water[l]; a[root].WaterL = water[l]; a[root].WaterR = water[l]; a[root].Maxh = 0; return; } int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); update(root, true); } void init(int x) { n = x; root = size = 0; for (int i = 1; i <= n; i++) scanf("%lf", &water[i]); for (int i = 1; i <= n - 1; i++) scanf("%lf", &block[i]); build(root, 1, n); } ld querySum(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].Sum; pushdown(root); int mid = (l + r) / 2; ld ans = 0; if (mid >= ql) ans += querySum(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) ans += querySum(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); return ans; } ld querySum(int l, int r) { return querySum(root, 1, n, l, r); } void modifyLeft(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { puttag(root, cur, 1); chkmax(cur, max(a[root].Maxh, block[a[root].l - 1])); return; } pushdown(root); int mid = (l + r) / 2; if (mid + 1 <= qr) modifyLeft(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); if (mid >= ql) modifyLeft(a[root].lc, l, mid, ql, min(mid, qr)); update(root, false); } void modifyLeft(int l, int r, ld tag) { cur = tag, modifyLeft(root, 1, n, l, r); } void modifyRight(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { puttag(root, cur, 2); chkmax(cur, max(a[root].Maxh, block[a[root].r])); return; } pushdown(root); int mid = (l + r) / 2; if (mid >= ql) modifyRight(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) modifyRight(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); update(root, false); } void modifyRight(int l, int r, ld tag) { cur = tag, modifyRight(root, 1, n, l, r); } void queryLeft(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { res += getvolLeft(root, cur); chkmax(cur, max(a[root].Maxh, block[a[root].l - 1])); return; } pushdown(root); int mid = (l + r) / 2; if (mid + 1 <= qr) queryLeft(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); if (mid >= ql) queryLeft(a[root].lc, l, mid, ql, min(mid, qr)); } ld queryLeft(int l, int r, ld val) { cur = val, res = 0; queryLeft(root, 1, n, l, r); return res; } void queryRight(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { res += getvolRight(root, cur); chkmax(cur, max(a[root].Maxh, block[a[root].r])); return; } pushdown(root); int mid = (l + r) / 2; if (mid >= ql) queryRight(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) queryRight(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); } ld queryRight(int l, int r, ld val) { cur = val, res = 0; queryRight(root, 1, n, l, r); return res; } void modifyBlock(int root, int l, int r, int pos, ld val) { int mid = (l + r) / 2; pushdown(root); if (mid > pos) modifyBlock(a[root].lc, l, mid, pos, val); if (mid + 1 <= pos) modifyBlock(a[root].rc, mid + 1, r, pos, val); block[pos] = val; update(root, true); } void modifyBlock(int pos, ld val) { if (val > block[pos] - eps) return; modifyBlock(root, 1, n, pos, val); } int findLeft(int root, int l, int r, int pos, ld val) { if (l == r) { if (fabs(a[root].Max - val) <= eps && fabs(a[root].Min - val) <= eps && block[l] <= val - eps) return l; else return l + 1; } pushdown(root); int mid = (l + r) / 2; if (r <= pos) { if (fabs(a[root].Max - val) <= eps && fabs(a[root].Min - val) <= eps && block[r] <= val - eps && a[root].Maxh <= val - eps) return l; if (fabs(a[a[root].rc].Max - val) <= eps && fabs(a[a[root].rc].Min - val) <= eps && block[r] <= val - eps && a[a[root].rc].Maxh <= val - eps) return findLeft(a[root].lc, l, mid, pos, val); else return findLeft(a[root].rc, mid + 1, r, pos, val); } if (mid + 1 <= pos) { int tmp = findLeft(a[root].rc, mid + 1, r, pos, val); if (tmp != mid + 1) return tmp; } return findLeft(a[root].lc, l, mid, pos, val); } int findLeft(int pos, ld val) { if (pos == 0) return 1; else return findLeft(root, 1, n, pos, val); } int findRight(int root, int l, int r, int pos, ld val) { if (l == r) { if (fabs(a[root].Max - val) <= eps && fabs(a[root].Min - val) <= eps && block[l - 1] <= val - eps) return l; else return l - 1; } pushdown(root); int mid = (l + r) / 2; if (l >= pos) { if (fabs(a[root].Max - val) <= eps && fabs(a[root].Min - val) <= eps && block[l - 1] <= val - eps && a[root].Maxh <= val - eps) return r; if (fabs(a[a[root].lc].Max - val) <= eps && fabs(a[a[root].lc].Min - val) <= eps && block[l - 1] <= val - eps && a[a[root].lc].Maxh <= val - eps) return findRight(a[root].rc, mid + 1, r, pos, val); else return findRight(a[root].lc, l, mid, pos, val); } if (mid >= pos) { int tmp = findRight(a[root].lc, l, mid, pos, val); if (tmp != mid) return tmp; } return findRight(a[root].rc, mid + 1, r, pos, val); } int findRight(int pos, ld val) { if (pos == n + 1) return n; else return findRight(root, 1, n, pos, val); } void addToRight(int root) { size++; a[size].l = a[size - 1].l; a[size].r = a[root].r; a[size].len = a[size - 1].len + a[root].len; a[size].lc = size - 1; a[size].rc = root; update(size, true); } void addToLeft(int root) { size++; a[size].l = a[root].l; a[size].r = a[size - 1].r; a[size].len = a[root].len + a[size - 1].len; a[size].lc = root; a[size].rc = size - 1; update(size, true); } void Extract(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { if (vis) addToRight(root); else { vis = true; a[++size] = a[root]; } return; } int mid = (l + r) / 2; if (mid >= ql) Extract(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) Extract(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); } int findRightmost(int root, int l, int r, int pos, ld vol) { if (l == r) { addToRight(root); if (getvolLeft(size, a[size].WaterR) - a[size].Sum <= vol + eps) return l; else { size--; return l - 1; } } pushdown(root); int mid = (l + r) / 2; if (l >= pos) { addToRight(root); if (getvolLeft(size, a[size].WaterR) - a[size].Sum <= vol + eps) return r; size--; addToRight(a[root].lc); if (getvolLeft(size, a[size].WaterR) - a[size].Sum <= vol + eps) return findRightmost(a[root].rc, mid + 1, r, pos, vol); else { size--; return findRightmost(a[root].lc, l, mid, pos, vol); } } if (mid >= pos) { int tmp = findRightmost(a[root].lc, l, mid, pos, vol); if (tmp != mid) return tmp; } return findRightmost(a[root].rc, mid + 1, r, pos, vol); } int findRightmost(int ql, int qr, ld vol) { int oldsize = size; vis = false, Extract(root, 1, n, ql, qr); int ans = findRightmost(root, 1, n, qr + 1, vol); size = oldsize; return ans; } int findLeftmost(int root, int l, int r, int pos, ld vol) { if (l == r) { addToLeft(root); if (getvolRight(size, a[size].WaterL) - a[size].Sum <= vol + eps) return l; else { size--; return l + 1; } } pushdown(root); int mid = (l + r) / 2; if (r <= pos) { addToLeft(root); if (getvolRight(size, a[size].WaterL) - a[size].Sum <= vol + eps) return l; size--; addToLeft(a[root].rc); if (getvolRight(size, a[size].WaterL) - a[size].Sum <= vol + eps) return findLeftmost(a[root].lc, l, mid, pos, vol); else { size--; return findLeftmost(a[root].rc, mid + 1, r, pos, vol); } } if (mid + 1 <= pos) { int tmp = findLeftmost(a[root].rc, mid + 1, r, pos, vol); if (tmp != mid + 1) return tmp; } return findLeftmost(a[root].lc, l, mid, pos, vol); } int findLeftmost(int ql, int qr, ld vol) { int oldsize = size; vis = false, Extract(root, 1, n, ql, qr); int ans = findLeftmost(root, 1, n, ql - 1, vol); size = oldsize; return ans; } int floodLeft(int root, int l, int r, int ql, int qr, ld vol) { if (r < ql) return r + 1; if (l == r) { cur += a[root].Sum; if (a[root].WaterL * (qr - l + 1) - cur <= vol + eps) return l; else { cur -= a[root].Sum; return l + 1; } } pushdown(root); int mid = (l + r) / 2; if (l >= ql && r <= qr) { cur += a[root].Sum; if (a[root].WaterL * (qr - l + 1) - cur <= vol + eps) return l; cur += a[a[root].rc].Sum - a[root].Sum; if (a[a[root].rc].WaterL * (qr - a[a[root].rc].l + 1) - cur <= vol + eps) return floodLeft(a[root].lc, l, mid, ql, qr, vol); else { cur -= a[a[root].rc].Sum; return floodLeft(a[root].rc, mid + 1, r, ql, qr, vol); } } if (mid + 1 <= qr) { int tmp = floodLeft(a[root].rc, mid + 1, r, ql, qr, vol); if (tmp != mid + 1) return tmp; } return floodLeft(a[root].lc, l, mid, ql, qr, vol); } void floodLeft(int ql, int qr, ld vol) { ld tmp = querySum(qr, qr); vol -= queryLeft(ql, qr, tmp) - querySum(ql, qr); modifyLeft(ql, qr, tmp); cur = 0; int pos = floodLeft(root, 1, n, ql, qr, vol); modifyLeft(ql, qr, (vol + querySum(pos, qr)) / (qr - pos + 1)); } int floodRight(int root, int l, int r, int ql, int qr, ld vol) { if (l > qr) return l - 1; if (l == r) { cur += a[root].Sum; if (a[root].WaterR * (l - ql + 1) - cur <= vol + eps) return l; else { cur -= a[root].Sum; return l - 1; } } pushdown(root); int mid = (l + r) / 2; if (l >= ql && r <= qr) { cur += a[root].Sum; if (a[root].WaterR * (r - ql + 1) - cur <= vol + eps) return r; cur += a[a[root].lc].Sum - a[root].Sum; if (a[a[root].lc].WaterR * (a[a[root].lc].r - ql + 1) - cur <= vol + eps) return floodRight(a[root].rc, mid + 1, r, ql, qr, vol); else { cur -= a[a[root].lc].Sum; return floodRight(a[root].lc, l, mid, ql, qr, vol); } } if (ql <= mid) { int tmp = floodRight(a[root].lc, l, mid, ql, qr, vol); if (tmp != mid) return tmp; } return floodRight(a[root].rc, mid + 1, r, ql, qr, vol); } void floodRight(int ql, int qr, ld vol) { ld tmp = querySum(ql, ql); vol -= queryRight(ql, qr, tmp) - querySum(ql, qr); modifyRight(ql, qr, tmp); cur = 0; int pos = floodRight(root, 1, n, ql, qr, vol); modifyRight(ql, qr, (vol + querySum(ql, pos)) / (pos - ql + 1)); } } ST; int main() { int n, q; read(n), read(q); ST.init(n); for (int i = 1; i <= q; i++) { int opt, pos; read(opt), read(pos); if (opt == 2) { printf("%.8lf\n", ST.querySum(pos, pos)); continue; } ld h; scanf("%lf", &h); ST.modifyBlock(pos, h); ld pre = ST.querySum(pos, pos), suf = ST.querySum(pos + 1, pos + 1); if (pre > suf + eps && pre > ST.block[pos] + eps) { int l = ST.findLeft(pos - 1, pre); ld vol = ST.querySum(l, pos) - ST.queryLeft(l, pos, h); ST.modifyLeft(l, pos, h); int r = ST.findRightmost(l, pos, vol); ST.floodLeft(l, r, vol); } else if (suf > pre + eps && suf > ST.block[pos] + eps) { int r = ST.findRight(pos + 2, suf); ld vol = ST.querySum(pos + 1, r) - ST.queryRight(pos + 1, r, h); ST.modifyRight(pos + 1, r, h); int l = ST.findLeftmost(pos + 1, r, vol); ST.floodRight(l, r, vol); } } for (int i = 1; i <= n; i++) printf("%.8lf ", ST.querySum(i, i)); return 0; } // O(N ^ 2) BruteForce #include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; const long double eps = 1e-12; typedef long long ll; typedef long double ld; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, q; ld a[MAXN], b[MAXN]; ld sum(int l, int r) { ld ans = 0; for (int i = l; i <= r; i++) ans += a[i]; return ans; } ld VolumeFromLeft(int l, int r, ld righth) { ld Max = righth, ans = 0; for (int i = r; i >= l; i--) { ans += Max; chkmax(Max, b[i - 1]); } return ans; } ld VolumeFromRight(int l, int r, ld lefth) { ld Max = lefth, ans = 0; for (int i = l; i <= r; i++) { ans += Max; chkmax(Max, b[i]); } return ans; } void FloodFromLeft(int l, int r, ld righth) { ld Max = righth; for (int i = r; i >= l; i--) { a[i] = Max; chkmax(Max, b[i - 1]); } } void FloodFromRight(int l, int r, ld lefth) { ld Max = lefth; for (int i = l; i <= r; i++) { a[i] = Max; chkmax(Max, b[i]); } } int main() { read(n), read(q); for (int i = 1; i <= n; i++) scanf("%Lf", &a[i]); for (int i = 1; i <= n - 1; i++) scanf("%Lf", &b[i]); for (int i = 1; i <= q; i++) { int opt, pos; read(opt), read(pos); if (opt == 2) { printf("%.10Lf\n", a[pos]); continue; } ld h; scanf("%Lf", &h); chkmin(b[pos], h); if (a[pos] > a[pos + 1] + eps && a[pos] > b[pos] + eps) { int l = pos; while (l >= 2 && fabsl(a[pos] - a[l - 1]) <= eps && a[pos] > b[l - 1] + eps) l--; ld volume = sum(l, pos) - VolumeFromLeft(l, pos, h); FloodFromLeft(l, pos, h); int lp = pos, rp = n; while (lp < rp) { int mid = (lp + rp + 1) / 2; if (VolumeFromLeft(l, mid, a[mid]) - sum(l, mid) <= volume + eps) lp = mid; else rp = mid - 1; } int r = lp; ld lv = a[r], rv = 100; while (lv + eps < rv) { ld mid = (lv + rv) / 2; if (VolumeFromLeft(l, r, mid) - sum(l, r) <= volume + eps) lv = mid; else rv = mid; } FloodFromLeft(l, r, (lv + rv) / 2); } else if (a[pos + 1] > a[pos] + eps && a[pos + 1] > b[pos] + eps) { int r = pos + 1; while (r < n && fabsl(a[pos + 1] - a[r + 1]) <= eps && a[pos + 1] > b[r] + eps) r++; ld volume = sum(pos + 1, r) - VolumeFromRight(pos + 1, r, h); FloodFromRight(pos + 1, r, h); int lp = 1, rp = pos + 1; while (lp < rp) { int mid = (lp + rp) / 2; if (VolumeFromRight(mid, r, a[mid]) - sum(mid, r) <= volume + eps) rp = mid; else lp = mid + 1; } int l = lp; ld lv = a[l], rv = 100; while (lv + eps < rv) { ld mid = (lv + rv) / 2; if (VolumeFromRight(l, r, mid) - sum(l, r) <= volume + eps) lv = mid; else rv = mid; } FloodFromRight(l, r, (lv + rv) / 2); } } for (int i = 1; i <= n; i++) printf("%.10Lf ", a[i]); return 0; }