高手。link
惯性思维很容易想到 Hall 定理 + 线段树 去处理,我一直想了 2h+,事实上有另外一种思路。
由于保留的所有区间都覆盖了位置 \(i\),我们考虑贪心做最大匹配:从左到右扫描每个位置,优先用 \(r\) 小的区间做匹配。
这样有个好处,我们可以把匹配的位置分为 \(\le i\) 和 \(\ge i + 1\) 两部分,这两部分有很大的独立性。
我们考虑从左到右扫描线,从右到左进行贪心匹配(即优先匹配 \(l\) 更大的区间)。考虑 \(\ge i + 1\) 的部分,根据 Hall 定理判定匹配的合法性,开一棵线段树维护每个前缀的左部点数量减去右部点数量的最大值。如果最大值 \(\ge 0\),考虑找到第一个最大值的位置 \(p\),再找到 \(r_j\le p\) 的满足 \(l_j\) 最小(优先级最小)的区间 \(j\),然后将对应的匹配移到 \(\le i\) 的部分。删掉的匹配数为最大值减去 \([i + 1, l_j - 1]\) 的最大值,重复此流程即可。
分析复杂度。发现每次更新一次匹配,线段树上至少有一个节点的右儿子最大值从大于左儿子最大值变为不超过左儿子最大值,所以总时间复杂度为 \(\mathcal O(n\log^2 n)\)。
-
理清思路,不要被假做法害了。
-
如果实在想不到就换个方向,换可小可大。
点击查看代码
#include <bits/stdc++.h>
#define ll int
#define LL long long
#define uLL unsigned LL
#define fi first
#define se second
#define mkp make_pair
#define pir pair<ll, ll>
#define pb push_back
#define i128 __int128
using namespace std;
char buf[1 << 22], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF :
// *p1++)
template <class T>
const inline void rd(T &x) {char ch;bool neg = 0;while (!isdigit(ch = getchar()))if (ch == '-')neg = 1;x = ch - '0';while (isdigit(ch = getchar())) x = (x << 1) + (x << 3) + ch - '0';if (neg)x = -x;
}
const ll maxn = 1e5 + 10, M = 1e6 + 10, mod = 1e9 + 7;
const LL inf = 1e18;
ll power(ll a, ll b = mod - 2, ll p = mod) {ll s = 1;while (b) {if (b & 1)s = 1ll * s * a % p;a = 1ll * a * a % p, b >>= 1;}return s;
}
template <class T, class _T>
const inline ll pls(const T x, const _T y) { return x + y >= mod ? x + y - mod : x + y; }
template <class T, class _T>
const inline ll mus(const T x, const _T y) { return x < y ? x + mod - y : x - y; }
template <class T, class _T>
const inline void add(T &x, const _T y) { x = x + y >= mod ? x + y - mod : x + y; }
template <class T, class _T>
const inline void sub(T &x, const _T y) { x = x < y ? x + mod - y : x - y; }
template <class T, class _T>
const inline void chkmax(T &x, const _T y) { x = x < y ? y : x; }
template <class T, class _T>
const inline void chkmin(T &x, const _T y) { x = x < y ? x : y; }ll T, n, m, a[maxn], l[maxn], r[maxn], c[maxn], b[maxn];
LL sum;
vector <ll> vecl[maxn], vecr[maxn];struct SGT {LL tag[maxn << 2]; pair <LL, ll> mx[maxn << 2];void addtag(ll p, LL v) { mx[p].fi += v, tag[p] += v; }void pushdown(ll p) {addtag(p << 1, tag[p]), addtag(p << 1|1, tag[p]);tag[p] = 0;}void modify(ll p, ll l, ll r, ll x, ll v) {if(l >= x) return addtag(p, v);pushdown(p); ll mid = l + r >> 1;if(x <= mid) modify(p << 1, l, mid, x, v);modify(p << 1|1, mid + 1, r, x, v);mx[p] = max(mx[p << 1], mx[p << 1|1]);}void build(ll p, ll l, ll r) {mx[p] = mkp(0ll, -l), tag[p] = 0;if(l == r) return; ll mid = l + r >> 1;build(p << 1, l, mid), build(p << 1|1, mid + 1, r);}LL query(ll p, ll l, ll r, ll x) {if(r <= x) return mx[p].fi;if(x < l) return -inf;pushdown(p); ll mid = l + r >> 1;return max(query(p << 1, l, mid, x), query(p << 1|1, mid + 1, r, x));}
} tr1, tr2;set <pir> st[maxn];
struct _SGT {pir mn[maxn << 2];void modify(ll p, ll l, ll r, ll x, pir t, ll v) {if(l == r) {if(v == 1) st[l].insert(t);else st[l].erase(t);mn[p] = st[l].empty()? mkp(n + 1, 0) : *st[l].begin();return;} ll mid = l + r >> 1;if(x <= mid) modify(p << 1, l, mid, x, t, v);else modify(p << 1|1, mid + 1, r, x, t, v);mn[p] = min(mn[p << 1], mn[p << 1|1]);}pir query(ll p, ll l, ll r, ll x) {if(r <= x) return mn[p];ll mid = l + r >> 1;if(x <= mid) return query(p << 1, l, mid, x);return min(query(p << 1, l, mid, x), query(p << 1|1, mid + 1, r, x));}
} tr3;void solve() {rd(n), rd(m); sum = 0;tr1.build(1, 1, n), tr2.build(1, 1, n);for(ll i = 1; i <= n; i++) {rd(a[i]), vecl[i].clear(), vecr[i].clear();tr1.modify(1, 1, n, i, -a[i]);}for(ll i = 1; i <= m; i++) {rd(l[i]), rd(r[i]), rd(c[i]);vecl[l[i]].pb(i), vecr[r[i]].pb(i);}for(ll i = 1; i <= n; i++) st[i].clear();for(ll i = 1; i <= 4 * n; i++) tr3.mn[i] = mkp(n + 1, 0);for(ll i = 1; i <= n; i++) {for(ll j: vecr[i - 1]) {sum -= c[j];tr2.modify(1, 1, n, n - l[j] + 1, -c[j]);}tr1.modify(1, 1, n, i, a[i]);tr2.modify(1, 1, n, n - i + 1, -a[i]);for(ll j: vecl[i]) {sum += c[j], b[j] = c[j];tr1.modify(1, 1, n, r[j], c[j]);tr3.modify(1, 1, n, r[j], mkp(l[j], j), 1);}while(tr1.mx[1].fi > 0) {ll pos = -tr1.mx[1].se, id = tr3.query(1, 1, n, pos).se;LL tmp = max(0ll, tr1.query(1, 1, n, pos - 1));ll w = min((LL) b[id], tr1.mx[1].fi - tmp);b[id] -= w, tr1.modify(1, 1, n, r[id], -w);tr2.modify(1, 1, n, n - l[id] + 1, w);if(!b[id]) tr3.modify(1, 1, n, r[id], mkp(l[id], id), -1);}printf("%lld ", sum - max(0ll, tr2.mx[1].fi));} puts("");
}int main() {rd(T); while(T--) solve();return 0;
}