Description
给出一个长度为 n n n 宽度为 1 1 1,高度无限的水箱,有 n − 1 n - 1 n−1 个挡板将其分为 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} j≤hi−1时,显然第 i − 1 i-1 i−1列的高度与第 i i i列没关系,可以从 [ 0 , h i − 1 ] [0,h_{i-1}] [0,hi−1]转移。
- 当 j > h i − 1 j > h_{i-1} j>hi−1时,显然只能从 f i − 1 , j f_{i-1,j} fi−1,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;
}