• 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)

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

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

    (valle sum),则 (r) 会被影响到。

    为什么呢?因为如果会影响到 (r),记修改之后的 (a[r]=k),那么有 (forall iin[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) 水量填入 (lsim r)。也就是说,我们要找到一个最小的 (s),满足条件:$$max(b[s]sim b[r-1],a[r])×(r-s+1)-(sum_{i=s}^ra[i])le sum-val$$

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

    暴力实现的时间复杂度为 (O(n^2log 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(nlog^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
    ", ans);
    		}
    	}
    	for (i = 1; i <= n; i++)
    	{
    		double ans = asksum(1, n, i, i, 1);
    		printf("%.8lf ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    POJ 2516 Minimum Cost [最小费用最大流]
    ZOJ 3407 Doraemon's Cake Machine [数学]
    ZOJ 2404 Going Home 【最小费用最大流】
    POJ 3422 Kaka's Matrix Travels 【最小费用最大流】
    树状数组的整理
    Day35 python基础--并发编程基础4
    Day34 python基础--并发编程基础3
    Day33 python基础--并发编程基础2
    Day32 python基础--并发编程基础1
    Day31 python基础--网络编程基础-socketserver
  • 原文地址:https://www.cnblogs.com/cyf32768/p/12402974.html
Copyright © 2020-2023  润新知