「LOJ6032」「雅礼集训 2017 Day2」水箱-DP+线段树

Description

给出一个长度为 n n n 宽度为 1 1 1,高度无限的水箱,有 n − 1 n - 1 n1 个挡板将其分为 n n n 个 1 - 1 的小格,然后向每个小格中注水,水如果超过挡板就会溢出到挡板的另一边,这里的水是满足物理定律的(在无挡板阻拦的情况下会向低处流),现在有 m m m 个条件 ( i , y , k ) (i, y, k) (i,y,k),表示从左到右数的第 i i i 个格子中,在高度为 y + 0.5 y + 0.5 y+0.5 的地方是否有水, k = 1 k = 1 k=1 表示有水, k = 0 k = 0 k=0 表示没有水,请求出这 m m m 个条件最多能同时满足多少个条件。本题有多组数据。

Solution

考虑朴素 D P DP DP。设 f i , j f_{i,j} fi,j表示填到了第 i i i列,第 i i i列高度为 j j j的最大收益。

  • j ≤ h i − 1 j \leq h_{i-1} jhi1时,显然第 i − 1 i-1 i1列的高度与第 i i i列没关系,可以从 [ 0 , h i − 1 ] [0,h_{i-1}] [0,hi1]转移。
  • j > h i − 1 j > h_{i-1} j>hi1时,显然只能从 f i − 1 , j f_{i-1,j} fi1,j转移。

用线段树维护 D P DP DP数组,只用支持区间覆盖,区间加法,区间求 M a x Max Max即可。

#include <bits/stdc++.h>
using namespace std;

inline int gi()
{
	char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	int sum = 0;
	while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
	return sum;
}

const int maxn = 100005;

int n, m, h[maxn], y[maxn], *q[maxn * 2], tot;
vector<int> vec[2][maxn];

#define mid ((l + r) >> 1)
#define lch (s << 1)
#define rch (s << 1 | 1)

int Max[maxn << 4], lzy1[maxn << 4], lzy2[maxn << 4];

inline void mdf1(int s, int x) {Max[s] = x; lzy1[s] = x; lzy2[s] = 0;}
inline void mdf2(int s, int x) {Max[s] += x; lzy2[s] += x;}

inline void pushdown(int s)
{
	if (~lzy1[s]) mdf1(lch, lzy1[s]), mdf1(rch, lzy1[s]), lzy1[s] = -1;
	if (lzy2[s]) mdf2(lch, lzy2[s]), mdf2(rch, lzy2[s]), lzy2[s] = 0;
}

void build(int s, int l, int r)
{
	Max[s] = lzy2[s] = 0; lzy1[s] = -1;
	if (l == r) return ;
	build(lch, l, mid);
	build(rch, mid + 1, r);
}

void cover(int s, int l, int r, int ql, int qr, int x)
{
	if (ql <= l && r <= qr) return mdf1(s, x);
	pushdown(s);
	if (ql <= mid) cover(lch, l, mid, ql, qr, x);
	if (mid + 1 <= qr) cover(rch, mid + 1, r, ql, qr, x);
	Max[s] = max(Max[lch], Max[rch]);
}

void insert(int s, int l, int r, int ql, int qr, int x)
{
	if (ql <= l && r <= qr) return mdf2(s, x);
	pushdown(s);
	if (ql <= mid) insert(lch, l, mid, ql, qr, x);
	if (mid + 1 <= qr) insert(rch, mid + 1, r, ql, qr, x);
	Max[s] = max(Max[lch], Max[rch]);
}

int query(int s, int l, int r, int ql, int qr)
{
	if (ql <= l && r <= qr) return Max[s];
	pushdown(s);
	int res = 0;
	if (ql <= mid) res = max(res, query(lch, l, mid, ql, qr));
	if (mid + 1 <= qr) res = max(res, query(rch, mid + 1, r, ql, qr));
	return res;
}

int main()
{
	int T = gi();
	while (T--) {
		n = gi(); m = gi(); int zero = 0, Inf = 1 << 30; q[1] = &zero; q[tot = 2] = &Inf;
		for (int i = 1; i < n; ++i) h[i] = gi(), q[++tot] = &h[i];
		for (int i = 1; i <= n; ++i) vec[0][i].clear(), vec[1][i].clear();
		for (int x, k, i = 1; i <= m; ++i) {
		    x = gi(); y[i] = gi(); k = gi(); y[i] += k;
			vec[k][x].push_back(i); q[++tot] = &y[i];
		}
		
		sort(q + 1, q + tot + 1, [](int *a, int *b) {return *a < *b;});
		int N = 1;
		for (int lst = *q[1], i = 1; i <= tot; ++i)
			if (lst != *q[i]) lst = *q[i], *q[i] = ++N;
			else *q[i] = N;

		build(1, 1, N);
		for (int i = 1; i <= n; ++i) {
			if (i > 1) {
				int Max = query(1, 1, N, 1, h[i - 1]);
				cover(1, 1, N, 1, h[i - 1], Max);
			}
			for (int j : vec[0][i])
				insert(1, 1, N, 1, y[j], 1);
			for (int j : vec[1][i])
				insert(1, 1, N, y[j], N, 1);
			//if (i <= 3)
			//for (int j = 1; j <= N; ++j) printf("%d ", query(1, 1, N, j, j));
			//puts("");
			//for (int j = 1; j <= N; ++j) query(1, 1, N, j, j);
			//printf("%d\n", query(1, 1, N, 1, N));
		}

		printf("%d\n", query(1, 1, N, 1, N));
	}
	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值