LOJ#3082「2019 集训队互测 Day 5」小水题(线段树)

Solution

考虑一次操作 2 x h 会发生什么。

首先可以明确一点,每次修改操作过后,水要么只会往右流,要么只会往左流,要么水位不会有任何改变。

这里考虑只往右流的情况:

\(a\) 是水位,\(b\) 是隔板高度,操作 2 x h 看作 \(b[x]=min(b[x],h)\)

往右流的条件:\(a[x]>max(a[x+1],h)\)

我们发现,当水从 \(x\) 流向 \(x+1\) 时,\(a[x]\) 会减少,此时可能导致 \(a[x-1]>max(b[x-1],a[x])\),也就是导致 \(x-1\) 的水流向 \(x\),以此类推,我们可以找到本次修改影响范围的左端点 \(l\)

\(l\) 需要满足条件:\(a[l]\sim a[x]\) 全部相等,且 \(b[l]\sim b[x-1]\) 都小于 \(a[x]\)

接下来要找到影响范围的右端点 \(r\)

考虑 \(r\) 需要满足什么条件。我们判断 \(r\) 是否会被影响到的时候,可以假装 \(b[l-1]\)\(b[r]\) 都是无限大。

我们先算出 \(a[l]\sim a[r]\) 在本次修改之前共有多少水,记为 \(sum\)

接下来,我们将 \(l\sim r\) 的水都抽干,然后算出 \(a[l]\sim a[r]\) 都取后缀最大值时,需要多少水,记为 \(val\)

后缀最大值的定义:\(a[i]=\max(b[i]\sim b[r-1],a[r])\),此处 \(a[r]\) 是修改之前的 \(a[r]\)

\(val\le sum\),则 \(r\) 会被影响到。

为什么呢?因为如果会影响到 \(r\),记修改之后的 \(a[r]=k\),那么有 \(\forall i\in[l,r],a[i]=\max(b[i]\sim b[r-1],k)\)

\(c[i]=\max(b[i]\sim b[r-1],k)\),首先水流静止状态下,不会有 \(c[i]>b[i]\)。如果存在 \(i<r,c[i]<b[i]\),那么前面的水就会流到 \(i\) 里面去,不会流到 \(r\)

找到 \(r\) 之后,我们让 \(a[r]\) 还是修改之前的水量,然后把 \(a[l-1]\sim a[r-1]\) 都填成后缀最大值。

然后我们要把剩下的 \(sum-val\) 水量填入 \(l\sim r\)。也就是说,我们要找到一个最小的 \(s\),满足条件:$$\max(b[s]\sim b[r-1],a[r])×(r-s+1)-(\sum_{i=s}^ra[i])\le sum-val$$

即把 \(s\sim r\) 都填成:$$\frac{(\sum_{i=s}^ra[i])+sum-val}{r-s+1}$$

暴力实现的时间复杂度为 \(O(n^2\log n)\)

考虑用线段树维护上述信息:

\(l\) 需要存下 \(A\) 的区间最大,最小值,\(B\) 的区间最值,然后直接在线段树上二分。

\(r\):记 \(query(l,r)\) 表示把 \(a[l]\sim a[r]\) 都填成后缀最大值,需要多少水。
\(r\) 满足条件:\(sum(l,r)\ge query(l,r)\)

这要怎么在线段树上二分呢?
在这里插入图片描述

如图,假设我们现在二分到了 \(r4\),那么 \(D,E,G,F\)\([l,r4]\) 的在原线段树上拆成的边界区间,\(A,B,C\) 是新建节点。

我们在二分的同时,要进行删点和加点操作。

这样就能在 \(O(\log n)\) 的时间内查询 \(query(l,r4)\) 的值(类似线段树维护单调上升子序列),在 \(O(1)\) 的时间查询 \(sum(l,r4)\) 的值。

而新建节点组成的树高显然是 \(O(\log n)\) 的,更新一个节点信息也只要 \(O(\log n)\)

再加上线段树上二分,总时间复杂度 \(O(\log^2 n)\)

\(a[l]\sim a[r]\) 都改成后缀最大值,只要给线段树上的 \(O(\log n)\) 个节点打上标记即可。

\(s\) 只要开一个全局变量,假设此时二分到了 \(s1\),我们要维护 \(\max(b[s1]\sim b[r-1],a[r])\)

总时间复杂度 \(O(n\log^2 n)\)

Code

#include <bits/stdc++.h>

using namespace std;

#define ld long double

const int e = 4e5 + 5;
const ld eps = 1e-12;

struct node
{
	int lc, rc, l, r, len, tag_op;
	ld sum, maxA, minA, tag_v, sumL, sumR, maxB, wl, wr;
}c[e];

ld a[e], b[e], now_c, ret, sum;
int n, q, pool, lst_p, now_l, now_r, t2;

inline ld askL(int x, ld cur)
{
	if (cur - c[x].maxB >= -eps) return c[x].len * cur;
	int lc = c[x].lc, rc = c[x].rc;
	ld t = b[c[lc].r];
	if (cur - c[lc].maxB >= -eps) return c[lc].len * cur + askL(rc, max(cur, t));
	return c[x].sumR + askL(lc, cur);
}

inline ld askR(int x, ld cur)
{
	if (cur - c[x].maxB >= -eps) return c[x].len * cur;
	int lc = c[x].lc, rc = c[x].rc;
	ld t = b[c[lc].r];
	if (cur - c[rc].maxB >= -eps) return c[rc].len * cur + askR(lc, max(cur, t));
	return c[x].sumL + askR(rc, cur);
}

inline void upt(int x, bool op)
{
	int lc = c[x].lc, rc = c[x].rc;
	ld t = b[c[lc].r];
	c[x].sum = c[lc].sum + c[rc].sum;
	c[x].maxA = max(c[lc].maxA, c[rc].maxA);
	c[x].minA = min(c[lc].minA, c[rc].minA);
	c[x].maxB = max(c[lc].maxB, max(c[rc].maxB, t));
	c[x].wl = c[lc].wl;
	c[x].wr = c[rc].wr;
	if (op)
	{
		c[x].sumL = askR(lc, max(c[rc].maxB, t));
		c[x].sumR = askL(rc, max(c[lc].maxB, t));
	}
}

inline void build(int l, int r, int &x)
{
	x = ++pool;
	c[x].l = l; c[x].r = r; c[x].len = r - l + 1;
	if (l == r)
	{
		c[x].sum = c[x].maxA = c[x].minA = a[l];
		c[x].wl = c[x].wr = a[l];
		return;
	}
	int mid = l + r >> 1;
	build(l, mid, c[x].lc);
	build(mid + 1, r, c[x].rc);
	upt(x, 1);
}

inline void addtag(int x, int op, ld v)
{
	int lc = c[x].lc, rc = c[x].rc;
	c[x].tag_op = op;
	c[x].tag_v = v;
	c[x].minA = v;
	c[x].maxA = max(v, c[x].maxB);
	if (op == 1)
	{
		c[x].sum = askL(x, v);
		c[x].wl = v;
		c[x].wr = max(c[x].maxB, v);
	}
	else
	{
		c[x].sum = askR(x, v);
		c[x].wr = v;
		c[x].wl = max(c[x].maxB, v);
	}
}

inline void pushdown(int x)
{
	if (c[x].tag_op)
	{
		int lc = c[x].lc, rc = c[x].rc, op = c[x].tag_op;
		ld v = c[x].tag_v, t = b[c[lc].r];
		if (op == 1)
		{
			addtag(lc, 1, v);
			addtag(rc, 1, max(c[lc].maxB, max(t, v)));
		}
		else
		{
			addtag(rc, 2, v);
			addtag(lc, 2, max(c[rc].maxB, max(t, v)));
		}
		c[x].tag_op = c[x].tag_v = 0;
	}
}

inline ld asksum(int l, int r, int s, int t, int x)
{
	if (l == s && r == t) return c[x].sum;
	pushdown(x);
	int mid = l + r >> 1;
	if (t <= mid) return asksum(l, mid, s, t, c[x].lc);
	else if (s > mid) return asksum(mid + 1, r, s, t, c[x].rc);
	else return asksum(l, mid, s, mid, c[x].lc) + asksum(mid + 1, r, mid + 1, t, c[x].rc);
}

inline bool check_L(int x, ld tmp)
{
	return fabs(c[x].maxA - c[x].minA) <= eps && fabs(c[x].maxA - tmp) <= eps
		&& c[x].maxA - max(c[x].maxB, b[c[x].r]) >= eps;
}

inline int find_L1(int l, int r, int ed, ld v, int x)
{
	if (l == r)
	{
		if (check_L(x, v)) return l;
		else return l + 1;
	}
	pushdown(x);
	int mid = l + r >> 1, lc = c[x].lc, rc = c[x].rc;
	if (ed <= mid) return find_L1(l, mid, ed, v, lc);
	else if (r <= ed)
	{
		if (check_L(x, v)) return l;
		if (check_L(rc, v)) return find_L1(l, mid, ed, v, lc);
		else return find_L1(mid + 1, r, ed, v, rc);
	}
	else
	{
		int x = find_L1(mid + 1, r, ed, v, rc);
		if (x != mid + 1) return x;
		else return find_L1(l, mid, ed, v, lc);
	}
}

inline bool check_R(int x, ld tmp)
{
	return fabs(c[x].maxA - c[x].minA) <= eps && fabs(c[x].maxA - tmp) <= eps
		&& c[x].maxA - max(c[x].maxB, b[c[x].l - 1]) >= eps;
}

inline int find_R1(int l, int r, int st, ld v, int x)
{
	if (l == r)
	{
		if (check_R(x, v)) return l;
		else return l - 1;
	}
	pushdown(x);
	int mid = l + r >> 1, lc = c[x].lc, rc = c[x].rc;
	if (mid < st) return find_R1(mid + 1, r, st, v, rc);
	else if (l >= st)
	{
		if (check_R(x, v)) return r;
		if (check_R(lc, v)) return find_R1(mid + 1, r, st, v, rc);
		else return find_R1(l, mid, st, v, lc);
	}
	else
	{
		int x = find_R1(l, mid, st, v, lc);
		if (x != mid) return x;
		else return find_R1(mid + 1, r, st, v, rc);
	}
}

inline void collect(int x, int lc, int rc)
{
	c[x].lc = lc; c[x].rc = rc;
	c[x].l = c[lc].l; c[x].r = c[rc].r;
	c[x].len = c[x].r - c[x].l + 1;
	c[x].tag_op = c[x].tag_v = 0;
	upt(x, 1);
}

inline void add_R(int x)
{
	pool++;
	if (pool == lst_p + 1) c[pool] = c[x];
	else collect(pool, pool - 1, x);
}

inline bool pd_R(int x)
{
	add_R(x);
	ld ar = c[pool].wr, sum = c[pool].sum, val = askR(pool, ar);
	return fabs(sum - val) <= eps || sum - val >= eps;
}

inline int se_R(int l, int r, int st, int x)
{
	if (l == r)
	{	 
		if (pd_R(x)) return l;
		else return l - 1;
	}
	pushdown(x);
	int mid = l + r >> 1, lc = c[x].lc, rc = c[x].rc;
	if (mid < st) return se_R(mid + 1, r, st, rc);
	else if (l >= st)
	{
		if (pd_R(x)) return r;
		pool--;
		if (pd_R(lc)) return se_R(mid + 1, r, st, rc);
		else
		{
			pool--;
			return se_R(l, mid, st, lc);
		}
	}
	else
	{
		int x = se_R(l, mid, st, lc);
		if (x != mid) return x;
		else return se_R(mid + 1, r, st, rc);
	}
} 

inline int find_R2(int st)
{
	lst_p = pool;
	int res = se_R(1, n, st, 1);
	pool = lst_p;
	return res;
}

inline void add_L(int x)
{
	pool++;
	if (pool == lst_p + 1) c[pool] = c[x];
	else collect(pool, x, pool - 1);
}

inline bool pd_L(int x)
{
	add_L(x);
	ld al = c[pool].wl, sum = c[pool].sum, val = askL(pool, al);
	return fabs(sum - val) <= eps || sum - val >= eps;
}

inline int se_L(int l, int r, int ed, int x)
{
	if (l == r)
	{	
		if (pd_L(x)) return l;
		else return l + 1;
	}
	pushdown(x);
	int mid = l + r >> 1, lc = c[x].lc, rc = c[x].rc;
	if (ed <= mid) return se_L(l, mid, ed, lc);
	else if (r <= ed)
	{
		if (pd_L(x)) return l;
		pool--;
		if (pd_L(rc)) return se_L(l, mid, ed, lc);
		else
		{
			pool--;
			return se_L(mid + 1, r, ed, rc);
		}
	}
	else
	{
		int x = se_L(mid + 1, r, ed, rc);
		if (x != mid + 1) return x;
		else return se_L(l, mid, ed, lc);
	}
} 

inline int find_L2(int ed)
{
	lst_p = pool;
	int res = se_L(1, n, ed, 1);
	pool = lst_p;
	return res;
}

inline void uptB(int l, int r, int s, ld v, int x)
{
	if (l == r)
	{
		b[l] = v;
		return;
	}
	pushdown(x);
	int mid = l + r >> 1;
	if (s <= mid) uptB(l, mid, s, v, c[x].lc);
	else uptB(mid + 1, r, s, v, c[x].rc);
	upt(x, 1);
}

inline void modify_R(int l, int r, int s, int t, int x)
{
	if (l == s && r == t)
	{
		if (r != now_r) now_c = max(now_c, b[r]);
		addtag(x, 2, now_c);
		now_c = max(now_c, c[x].maxB);
		return;
	}
	pushdown(x);
	int mid = l + r >> 1, lc = c[x].lc, rc = c[x].rc;
	if (t <= mid) modify_R(l, mid, s, t, lc);
	else if (s > mid) modify_R(mid + 1, r, s, t, rc);
	else modify_R(mid + 1, r, mid + 1, t, rc), modify_R(l, mid, s, mid, lc);
	upt(x, 0);
}

inline void modify_L(int l, int r, int s, int t, int x)
{
	if (l == s && r == t)
	{
		if (l != now_l) now_c = max(now_c, b[l - 1]);
		addtag(x, 1, now_c);
		now_c = max(now_c, c[x].maxB);
		return;
	}
	pushdown(x);
	int mid = l + r >> 1, lc = c[x].lc, rc = c[x].rc;
	if (t <= mid) modify_L(l, mid, s, t, lc);
	else if (s > mid) modify_L(mid + 1, r, s, t, rc);
	else modify_L(l, mid, s, mid, lc), modify_L(mid + 1, r, mid + 1, t, rc);
	upt(x, 0);
}

inline int query_L(int l, int r, int st, int ed, int x)
{
	if (l == r)
	{
		now_c = max(now_c, c[x].maxA);
		sum += c[x].maxA;
		if (now_c * (ed - l + 1) - sum - ret <= eps) return l;
		else return l + 1;
	}
	pushdown(x);
	int mid = l + r >> 1, lc = c[x].lc, rc = c[x].rc;
	if (ed <= mid) return query_L(l, mid, st, ed, lc);
	else if (mid < st) return query_L(mid + 1, r, st, ed, rc); 
	else if (st <= l && r <= ed)
	{
		if (max(now_c, c[x].maxA) * (ed - l + 1) - c[x].sum - sum - ret <= eps) 
		{
			now_c = max(now_c, c[x].maxA);
			sum += c[x].sum;
			return l;
		}
		if (max(now_c, c[rc].maxA) * (ed - mid) - c[rc].sum - sum - ret <= eps)
		{
			now_c = max(now_c, c[rc].maxA);
			sum += c[rc].sum;
			return query_L(l, mid, st, ed, lc);
		}
		else return query_L(mid + 1, r, st, ed, rc);
	}
	else
	{
		int x = query_L(mid + 1, r, st, ed, rc);
		if (x != mid + 1) return x; 
		return query_L(l, mid, st, ed, lc);
	}
}

inline int query_R(int l, int r, int st, int ed, int x)
{
	if (l == r)
	{
		now_c = max(now_c, c[x].maxA);
		sum += c[x].sum;	
		if (now_c * (r - st + 1) - sum - ret <= eps) return l;
		else return l - 1;
	}
	pushdown(x);
	int mid = l + r >> 1, lc = c[x].lc, rc = c[x].rc;
	if (mid < st) return query_R(mid + 1, r, st, ed, rc);
	else if (ed <= mid) return query_R(l, mid, st, ed, lc);
	else if (st <= l && r <= ed)
	{
		if (max(now_c, c[x].maxA) * (r - st + 1) - c[x].sum - sum - ret <= eps) 
		{
			now_c = max(now_c, c[x].maxA);
			sum += c[x].sum;
			return r;
		}
		if (max(now_c, c[lc].maxA) * (mid - st + 1) - c[lc].sum - sum - ret <= eps)
		{
			now_c = max(now_c, c[lc].maxA);
			sum += c[lc].sum;
			return query_R(mid + 1, r, st, ed, rc);
		}
		else return query_R(l, mid, st, ed, lc);
	}
	else
	{
		int x = query_R(l, mid, st, ed, lc);
		if (x != mid) return x; 
		return query_R(mid + 1, r, st, ed, rc);
	}
}

int main()
{
	scanf("%d%d", &n, &q);
	int i, x, pos, op, l, r, st, ed, tim = 0; double t; ld h;
	for (i = 1; i <= n; i++) scanf("%lf", &t), a[i] = t;
	for (i = 1; i < n; i++) scanf("%lf", &t), b[i] = t;
	build(1, n, x);
	while (q--)
	{
		scanf("%d%d", &op, &pos);
		if (op == 1)
		{
			scanf("%lf", &t); h = t;
			if (b[pos] - h <= eps) continue;
			uptB(1, n, pos, h, 1);
			ld a1 = asksum(1, n, pos, pos, 1), a2 = asksum(1, n, pos + 1, pos + 1, 1);
			if (a1 - h >= eps && a1 - a2 >= eps)
			{
				l = find_L1(1, n, pos, a1, 1);
				r = find_R2(l);
				
				ld ar = asksum(1, n, r, r, 1), lst_s = asksum(1, n, l, r, 1);
				now_c = ar; now_r = r;
				modify_R(1, n, l, r, 1);
				
				now_c = ar; 
				ret = lst_s - asksum(1, n, l, r, 1); sum = 0;
				
				st = query_L(1, n, l, r, 1);
				st = max(st, l);
				
				ld all = asksum(1, n, st, r, 1) + ret;
				now_c = all / (r - st + 1);
				
				modify_R(1, n, st, r, 1);
			}
			else if (a2 - h >= eps && a2 - a1 >= eps)
			{
				r = find_R1(1, n, pos + 1, a2, 1);
				l = find_L2(r);
				
				ld al = asksum(1, n, l, l, 1), lst_s = asksum(1, n, l, r, 1);
				now_c = al; now_l = l;
				modify_L(1, n, l, r, 1);
				
				now_c = al;
				ret = lst_s - asksum(1, n, l, r, 1); sum = 0;
				ed = query_R(1, n, l, r, 1);
				
				ld all = asksum(1, n, l, ed, 1) + ret;
				now_c = all / (ed - l + 1);
				modify_L(1, n, l, ed, 1);
			}
		}
		else
		{
			double ans = asksum(1, n, pos, pos, 1);
			printf("%.8lf\n", ans);
		}
	}
	for (i = 1; i <= n; i++)
	{
		double ans = asksum(1, n, i, i, 1);
		printf("%.8lf ", ans);
	}
	return 0;
}
posted @ 2020-03-03 16:22  花淇淋  阅读(336)  评论(0编辑  收藏  举报