【LOJ3082】「2019 集训队互测 Day 5」小水题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89923841

【题目链接】

【思路要点】

  • 考虑一次钻孔操作对全局水位的影响。
  • 注意到一次钻孔操作只会使得水向某一方向流动,以下认为水向右流动进行讨论。
  • 定义函数 q u e r y S u m ( l , r ) querySum(l,r) 表示区间 [ l , r ] [l,r] 的水位和。
  • 定义函数 q u e r y L e f t ( l , r , h ) queryLeft(l,r,h) 表示假设区间 [ l , r ] [l,r] 两侧的挡板高度无限,在区间中没有水的时候需要在 l l 处倒入多少水使得 r r 处的水位到达 h h
  • 定义操作 m o d i f y L e f t ( l , r , h ) modifyLeft(l,r,h) 表示假设区间 [ l , r ] [l,r] 两侧的挡板高度无限,抽空区间中的水,并在 l l 处倒入一定量的水,直到 r r 处的水位到达 h h
  • 假设一次钻孔操作 2   p o s   h 2\ pos\ h 使得 p o s pos 处的水将要流向 p o s + 1 pos+1
  • 首先,找到最小的 l l ,使得 [ l , p o s ] [l,pos] 内的水位相等,且挡板高度均不足水位高度。
  • 计算 v o l = q u e r y S u m ( l , p o s ) q u e r y L e f t ( l , p o s , h ) vol=querySum(l,pos)-queryLeft(l,pos,h) ,即最多可以流出的水量,并执行操作 m o d i f y L e f t ( l , p o s , h ) modifyLeft(l,pos,h)
  • 其次,找到最大的 r r ,使得 q u e r y L e f t ( l , r , a r ) q u e r y S u m ( l , r ) v o l queryLeft(l,r,a_r)-querySum(l,r)\leq vol ,即此次流动将会影响到的区间右端点。
  • 最后,找到最大的 v a l val ,使得 q u e r y L e f t ( l , r , v a l ) q u e r y S u m ( l , r ) v o l queryLeft(l,r,val)-querySum(l,r)\leq vol ,即最后 r r 处的水位,执行操作 m o d i f y L e f t ( l , p o s , v a l ) modifyLeft(l,pos,val) 即可。
  • 使用李超式线段树可以在 O ( L o g 2 N ) O(Log^2N) 的时间内实现 q u e r y S u m querySum q u e r y L e f t queryLeft m o d i f y L e f t modifyLeft 中的每一个功能,直接二分找到 l , r , v o l l,r,vol 可以得到 O ( N L o g 2 N + Q L o g 3 N ) O(NLog^2N+QLog^3N) 的时间复杂度。
  • 将二分改为在线段树上二分,时间复杂度降为 O ( N L o g 2 N + Q L o g 2 N ) O(NLog^2N+QLog^2N)

【代码】

// 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;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/89923841
今日推荐