您的位置:首页 > 产品设计 > UI/UE

【BZOJ4355】Play with Sequence

2018-01-18 13:19 330 查看
【题目链接】

点击打开链接

【思路要点】

题目中提到的操作均为区间操作,考虑使用线段树。
注意到数列中的数始终非负,因此3号操作可以看做询问最小值以及其出现次数。
2号操作并非线段树的一般操作,无法直接支持标记合并。
考虑一个被2号操作定位的区间,记区间最小值为\(Min\),严格次小值为\(Mim\),对该区间实行操作数为\(Val\)的2号操作。
若\(Min+Val≥0\),显然这个操作可以看做一个区间加(减)操作。
若\(Min+Val<0\)且\(Mim+Val>0\),我们可以将这个操作看作是对区间中最小值的整体加(减)操作。
若\(Mim+Val≤0\),那么这就意味着最小值和严格次小值将在本次操作后相等,为了重新得到区间严格次小值,我们暴力对该区间在线段树上的两个子节点分别操作一次,并将信息合并。
用势能分析法能够证明,这样的做法存在时间复杂度下界\(O(MLog^{2}N)\),并且实际运行往往表现出优于该复杂度的效率。证明详见国家集训队2016论文集之《区间最值操作与历史最值问题——杭州学军中学 吉如一》。

【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 300005;
const long long INF = 1e18;
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
struct info {long long Min, Mim; int Cnt; };
info operator + (info a, info b) {
info ans;
ans.Min = min(a.Min, b.Min);
ans.Mim = min(a.Mim, b.Mim);
ans.Cnt = 0;
if (a.Min != ans.Min) ans.Mim = min(ans.Mim, a.Min);
else ans.Cnt += a.Cnt;
if (b.Min != ans.Min) ans.Mim = min(ans.Mim, b.Min);
else ans.Cnt += b.Cnt;
return ans;
}
struct SegmentTree {
struct Node {
int lc, rc, tag;
long long val, delta;
info now;
} a[MAXN * 2];
int n, root, tot, value[MAXN];
void update(int root) {
a[root].now = a[a[root].lc].now + a[a[root].rc].now;
}
void build(int &root, int l, int r) {
root = ++tot;
if (l == r) {
a[root].now = (info) {value[l], INF, 1};
return;
}
int mid = (l + r) / 2;
build(a[root].lc, l, mid);
build(a[root].rc, mid + 1, r);
update(root);
}
void init(int x) {
n = x;
tot = root = 0;
build(root, 1, n);
}
void pushdown();
void cover(int root, int l, int r, long long val) {
a[root].tag = 1;
a[root].val = val;
a[root].delta = 0;
a[root].now = (info) {val, INF, r - l + 1};
}
void cover(int root, int l, int r, int ql, int qr, long long val) {
if (l == ql && r == qr) {
cover(root, l, r, val);
return;
}
pushdown(root, l, r);
int mid = (l + r) / 2;
if (mid >= ql) cover(a[root].lc, l, mid, ql, min(mid, qr), val);
if (mid + 1 <= qr) cover(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, val);
update(root);
}
void cover(int l, int r, long long val) {
cover(root, 1, n, l, r, val);
}
void add(int root, int l, int r, long long val) {
if (a[root].tag == 1) {
a[root].val += val;
a[root].delta = 0;
if (a[root].val < 0) a[root].val = 0;
a[root].now.Min = a[root].val;
} else {
if (a[root].tag == 0) {
a[root].tag = 2;
a[root].val = 0;
}
a[root].val += val;
a[root].now.Min += val;
a[root].now.Mim += val;
if (a[root].now.Min >= 0) return;
if (a[root].now.Mim > 0) {
a[root].delta -= a[root].now.Min;
a[root].now.Min = 0;
} else {
pushdown(root, l, r);
update(root);
}
}
}
void add(int root, int l, int r, int ql, int qr, long long val) {
if (l == ql && r == qr) {
add(root, l, r, val);
return;
}
pushdown(root, l, r);
int mid = (l + r) / 2;
if (mid >= ql) add(a[root].lc, l, mid, ql, min(mid, qr), val);
if (mid + 1 <= qr) add(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, val);
update(root);
}
void add(int l, int r, long long val) {
add(root, 1, n, l, r, val);
}
info query(int root, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return a[root].now;
pushdown(root, l, r);
int mid = (l + r) / 2;
if (ql > mid) return query(a[root].rc, mid + 1, r, ql, qr);
if (mid >= qr) return query(a[root].lc, l, mid, ql, qr);
return query(a[root].lc, l, mid, ql, mid) + query(a[root].rc, mid + 1, r, mid + 1, qr);
}
int query(int l, int r) {
info tmp = query(root, 1, n, l, r);
if (tmp.Min == 0) return tmp.Cnt;
else return 0;
}
void pushdown(int root, int l, int r) {
if (a[root].lc == 0) return;
if (a[root].delta) {
if (a[a[root].lc].now.Min == a[a[root].rc].now.Min) {
a[a[root].lc].delta += a[root].delta;
if (a[a[root].lc].tag == 1) a[a[root].lc].val += a[root].delta;
else a[a[root].lc].now.Min += a[root].delta;
a[a[root].rc].delta += a[root].delta;
if (a[a[root].rc].tag == 1) a[a[root].rc].val += a[root].delta;
else a[a[root].rc].now.Min += a[root].delta;
} else if (a[a[root].lc].now.Min < a[a[root].rc].now.Min) {
a[a[root].lc].delta += a[root].delta;
if (a[a[root].lc].tag == 1) a[a[root].lc].val += a[root].delta;
else a[a[root].lc].now.Min += a[root].delta;
} else {
a[a[root].rc].delta += a[root].delta;
if (a[a[root].rc].tag == 1) a[a[root].rc].val += a[root].delta;
else a[a[root].rc].now.Min += a[root].delta;
}
a[root].delta = 0;
}
int mid = (l + r) / 2;
if (a[root].tag == 1) {
cover(a[root].lc, l, mid, a[root].val);
cover(a[root].rc, mid + 1, r, a[root].val);
a[root].tag = 0;
a[root].val = 0;
} else if (a[root].tag == 2) {
add(a[root].lc, l, mid, a[root].val);
add(a[root].rc, mid + 1, r, a[root].val);
a[root].tag = 0;
a[root].val = 0;
}
update(root);
}
} ST;
int main() {
int n, m;
read(n), read(m);
for (int i = 1; i <= n; i++)
read(ST.value[i]);
ST.init(n);
for (int i = 1; i <= m; i++) {
int opt, l, r, val;
read(opt), read(l), read(r);
if (opt == 1) read(val), ST.cover(l, r, val);
if (opt == 2) read(val), ST.add(l, r, val);
if (opt == 3) writeln(ST.query(l, r));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: