线段树合并+树状数组
把0设成-1,问题就变成求最大前缀和。
考虑一个DP,记f[i]表示i隔板隔住了水,i之前最多满足多少条件。转移的时候枚举j表示[j,i]能是一个以j,i为左右端点的装水区间。
这样的问题是每次从新的i扫到一个j都要合并一遍区间里的所有标记,也就是一个区间会被合并多次。然而能够证明,不同的装水区间不超过O(n)个,且它们之间不会有交(端点可能相同)。
因此先找出这些区间,线段树维护一个区间的所有条件,求最大前缀和,合并就是直接线段树合并,这样总O(nlogn)。
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define N 200005
#define lowbit(_i) (_i&-_i)
#define mkp(_i,_j) make_pair(_i,_j)
using namespace std;
namespace runzhe2000
{
const int INF = 1<<29;
vector<pair<int,int> > vec[N], val[N];
int n, m, h[N], sta[N], stacnt, incnt, arr[N], arrcnt, sum, mx, f[N], cnt0, rank[N];
struct inter
{
int l, r, ans; inter *fa;
bool operator < (const inter &that) const
{
return r == that.r ? l < that.l : r > that.r;
}
}in[N<<1];
bool cmp_len(int a, int b){return in[a].r-in[a].l+1 < in[b].r-in[b].l+1;}
struct BIT
{
int t[N*10];
int query(int x)
{
int r = 0;
for(; x; x -= lowbit(x))
{
in[r].l < in[t[x]].l ? r = t[x] : 0;
}
return r;
}
void modi(int x, int v)
{
for(; x < N; x += lowbit(x))
{
if(in[v].r < in[t[x]].r || (in[v].r == in[t[x]].r && in[t[x]].l < in[v].l))
t[x] = v;
}
}
}T;
struct SEG
{
int t[N*10];
void build(int x, int l, int r)
{
if(l == r) {t[x] = h[l]; return;} int mid = (l+r)>>1;
build(x<<1,l,mid); build(x<<1|1,mid+1,r);
t[x] = max(t[x<<1], t[x<<1|1]);
}
int query(int x, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return t[x]; int mid = (l+r)>>1, ret = 0;
if(ql <= mid) ret = max(ret, query(x<<1,l,mid,ql,qr));
if(mid < qr) ret = max(ret, query(x<<1|1,mid+1,r,ql,qr));
return ret;
}
}S;
struct seg
{
seg *ch[2];
int sum, mx;
}mem[N*20], *tot, *null, *root[N];
seg *newseg()
{
seg *x = ++tot; *x = *null;
return x;
}
void init()
{
null = tot = mem;
null->ch[0] = null->ch[1] = null;
null->sum = null->mx = 0;
for(int i = 0; i <= incnt; i++)
root[i] = newseg();
}
void pushup(seg *x)
{
x->sum = x->ch[0]->sum + x->ch[1]->sum;
x->mx = max(x->ch[0]->mx, x->ch[0]->sum + x->ch[1]->mx);
}
void insert(seg *x, int l, int r, int p, int v)
{
if(l == r){x->sum += v; x->mx = max(x->sum, 0); return;} int mid = (l+r)>>1;
if(p <= mid)
{
if(x->ch[0] == null) x->ch[0] = newseg();
insert(x->ch[0], l, mid, p, v);
}
else
{
if(x->ch[1] == null) x->ch[1] = newseg();
insert(x->ch[1], mid+1, r, p, v);
}
pushup(x);
}
seg *merge(seg *x, seg *y, int l, int r)
{
if(x == null) return y;
if(y == null) return x;
seg *p = newseg();
if(l == r)
{
p->sum = x->sum + y->sum;
p->mx = max(0, p->sum);
return p;
}
int mid = (l+r)>>1;
p->ch[0] = merge(x->ch[0], y->ch[0], l, mid);
p->ch[1] = merge(x->ch[1], y->ch[1], mid+1, r);
pushup(p);
return p;
}
int query_sum(seg *x, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return x->sum; int mid = (l+r)>>1, ret = 0;
if(ql <= mid) ret += query_sum(x->ch[0], l, mid, ql, qr);
if(mid < qr) ret += query_sum(x->ch[1], mid+1, r, ql, qr);
return ret;
}
void query_mx(seg *x, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) {mx = max(mx, sum + x->mx); sum += x->sum; return;}
int mid = (l+r)>>1;
if(ql <= mid) query_mx(x->ch[0], l, mid, ql, qr);
if(mid < qr) query_mx(x->ch[1], mid+1, r, ql, qr);
}
void main()
{
int task; scanf("%d",&task);
for(; task--; )
{
scanf("%d%d",&n,&m);
for(int i = 1; i < n; i++)
{
scanf("%d",&h[i]);
arr[++arrcnt] = h[i];
for(; stacnt && h[sta[stacnt]] <= h[i]; )
{
in[++incnt] = (inter){sta[stacnt], i, 0, 0};
stacnt--;
}
in[++incnt] = (inter){sta[stacnt], i, 0, 0};
sta[++stacnt] = i;
}
for(; ~stacnt; stacnt--) in[++incnt] = (inter){sta[stacnt], n, 0, 0};
for(int i = 1, p, y, k; i <= m; i++)
{
scanf("%d%d%d",&p,&y,&k);
cnt0 += k == 0;
vec[p].push_back(mkp(y,k));
arr[++arrcnt] = y;
}
arr[++arrcnt] = h[0] = h[n] = INF;
arr[++arrcnt] = -1;
sort(arr+1, arr+1+arrcnt);
arrcnt = unique(arr+1, arr+1+arrcnt) - arr - 1;
for(int i = 1; i <= n; i++)
for(int j = 0, jj = vec[i].size(); j < jj; j++)
vec[i][j].first = lower_bound(arr+1, arr+1+arrcnt, vec[i][j].first) - arr;
for(int i = 0; i <= n; i++) h[i] = lower_bound(arr+1, arr+1+arrcnt, h[i]) - arr;
sort(in+1, in+1+incnt);
in[0].l = -INF; in[0].r = INF;
for(int i = 1; i <= incnt; i++)
{
in[i].fa = &in[T.query(in[i].l+1)];
T.modi(in[i].l+1, i);
}
for(int i = 1; i <= incnt; i++) rank[i] = i;
sort(rank+1, rank+1+incnt, cmp_len);
init();
S.build(1,0,n);
for(int ii = 1, i; ii <= incnt; ii++)
{
i = rank[ii];
int d, u = min(h[in[i].l], h[in[i].r]);
if(in[i].l + 1 == in[i].r)
{
for(int j = 0, jj = vec[in[i].r].size(); j < jj; j++)
{
insert(root[i], 1, arrcnt, vec[in[i].r][j].first, vec[in[i].r][j].second == 1 ? 1 : -1);
}
d = 1;
}
else d = S.query(1,0,n,in[i].l+1, in[i].r-1);
sum = 1 < d ? query_sum(root[i], 1, arrcnt, 1, d-1) : 0;
mx = 0; query_mx(root[i], 1, arrcnt, d, u-1);
in[i].ans = mx;
val[in[i].r].push_back(mkp(in[i].l, mx));
if(in[i].fa != &in[0]) root[in[i].fa-in] = merge(root[in[i].fa-in], root[i], 1, arrcnt);
}
for(int i = 1; i <= n; i++)
for(int j = 0, jj = val[i].size(); j < jj; j++)
f[i] = max(f[i], f[val[i][j].first] + val[i][j].second);
printf("%d\n",f[n]+cnt0);
stacnt = arrcnt = incnt = cnt0 = 0;
memset(f, 0, sizeof(f));
memset(T.t, 0, sizeof(T.t));
memset(S.t, 0, sizeof(S.t));
for(int i = 0; i <= n; i++) vec[i].clear(), val[i].clear();
}
}
}
int main()
{
runzhe2000::main();
}