【题解】FZOJ2697 -- 怨灵退治
题目大意(懒得概括,直接复制题面了):
在器灵有了异动的同时,灼热地狱的怨灵发生了暴动。作为怨灵的管理者,火焰猫燐决定消灭暴动的怨灵。有 \(n\) 群怨灵排成一排,燐会依次选择 \(m\) 段区间,消灭至多 \(k\) 只怨灵。
如果怨灵数量不足 \(k\),则会消灭尽量多的怨灵。
燐作为一只有特点的猫,它选择的区间是不会相互包含的。它想要知道它每秒最多能消灭多少怨灵。
\(m\le n\le 10^5\)
题解:
由标签可知,需要用到霍尔定理
把每次的区间当成二分图的左部,怨灵当成右部。
我们可以对于右部的每个区间验证,方法就是这个区间怨灵个数大于等于到目前为止所有完全在这个区间里面的那些区间要消灭的怨灵数量的和。
记怨灵数量的前缀和为 \(sum_i\),区间消灭的怨灵数量的前缀和为 \(sumv_i\)。
要求对于任意的 \(l, r(l\le r)\),都有 \(sum_r - sum_{l-1} \ge sumv_r - sumv_{l-1}\)
\(\rightarrow sum_r - sumv_r \ge sum_{l-1} - sumv_{l-1}\)
所以我们只要用线段树维护一下左区间 \(sum_{l-1} - sumv_{l-1}\) 的最大值和右区间 \(sum_r - sumv_r\) 判断两者大小关系即可。
时间复杂度 \(O(m\times\log m)\)
Code
#include <bits/stdc++.h>
#define mid (l + r >> 1)
#define FOR(i,j,k) for(int i=j; i<=k; ++i)
#define ROF(i,j,k) for(int i=j; i>=k; --i)
inline int read (void) {
int x = 0, f = 1, ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -f; ch = getchar(); }
while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
const int maxn = 100005;
const int maxm = 262145;
struct Node {
int v1, v2, mxv2, mnv1, ans;
} node[maxm];
inline void update (int k) {
node[k].ans = std::max (std::max (node[k<<1].ans, node[k<<1|1].ans), node[k<<1].mxv2 - node[k<<1|1].mnv1);
node[k].mxv2 = std::max (node[k<<1].mxv2, node[k<<1|1].mxv2);
node[k].mnv1 = std::min (node[k<<1].mnv1, node[k<<1|1].mnv1);
}
inline void lazy1 (int k, int v) {
node[k].v1 += v;
node[k].mnv1 += v;
node[k].ans -= v;
}
inline void lazy2 (int k, int v) {
node[k].v2 += v;
node[k].mxv2 += v;
node[k].ans += v;
}
inline void pushdown (int k) {
if(node[k].v1) {
lazy1 (k<<1, node[k].v1);
lazy1 (k<<1|1, node[k].v1);
node[k].v1 = 0;
}
if(node[k].v2) {
lazy2 (k<<1, node[k].v2);
lazy2 (k<<1|1, node[k].v2);
node[k].v2 = 0;
}
}
int a[maxn];
void build (int l, int r, int k=1) {
if(l == r) {
node[k].v1 = node[k].v2 = node[k].mnv1 = node[k].mxv2 = a[l];
node[k].ans = -1 << 30;
return ;
}
build (l, mid, k<<1);
build (mid+1, r, k<<1|1);
update (k);
}
void modify1 (int l, int r, int ql, int qr, int c, int k=1) {
if(ql <= l && r <= qr) {
lazy1 (k, c);
return ;
}
pushdown (k);
if(ql <= mid) modify1 (l, mid, ql, qr, c, k<<1);
if(mid < qr) modify1 (mid+1, r, ql, qr, c, k<<1|1);
update (k);
}
void modify2 (int l, int r, int ql, int qr, int c, int k=1) {
if(ql <= l && r <= qr) {
lazy2 (k, c);
return ;
}
pushdown (k);
if(ql <= mid) modify2 (l, mid, ql, qr, c, k<<1);
if(mid < qr) modify2 (mid+1, r, ql, qr, c, k<<1|1);
update (k);
}
int main (void) {
int n = read();
FOR(i,1,n) a[i] = a[i-1] + read();
build (0, n);
int m = read();
while(m--) {
int l = read(), r = read(), v = read();
modify1 (0, n, r, n, -v);
modify2 (0, n, l, n, -v);
if(node[1].ans <= 0) printf("%d\n", v);
else {
int res = node[1].ans;
printf("%d\n", v - res);
modify1 (0, n, r, n, res);
modify2 (0, n, l, n, res);
}
}
return 0;
}

浙公网安备 33010602011771号