HDU-5306 Gorgeous Sequence 解题报告
题意简述
¶0 x y t
: 令 ,其中: 。记作1 x y
: 输出 ,其中: 。记作2 x y
: 输出 。记作
数据范围:
题目简析
¶用线段树维护一段区间的 4 个标量:tag
, cnt
, max
, sum
。
max
: 区间内的最大值sum
: 区间内所有值的和tag
: 一个懒惰标记, 表示在该区间执行了一次 ,且 ;同时, 时还表示当前节点信息未被正确更新。cnt
: 当前区间中要删除的点的个数(见下文)。
注意到修改操作 (

Pushup
¶当一个叶子节点被删除时,我们要令其 tag
置为
12345void pushup(int o) { maxv[o] = std::max(maxv[lc], maxv[rc]); sumv[o] = sumv[lc] + sumv[rc]; cntv[o] = cntv[lc] + cntv[rc];}
Clear
¶清零操作步骤如下:
123456789101112void clear(int o, int tag) { if (maxv[o] <= tag) return; tagv[o] = 0; if (leav[o]) { sumv[o] = maxv[o] = 0; cntv[o] = 1; } else { clear(lc, tag); clear(rc, tag); pushup(o); }}
Maintain
¶再考虑维护操作。
max
的维护很简单,瞎搞下就好,问题在于 sum
的维护。由于执行 cnt
的作用就体现了。我们仅需执行
12345678910111213void maintain(int o, int tag) { // tagv[o]==0 表示当前节点未被正确更新 if (tagv[o]) return;
tagv[o] = tag;
// 如果节点 o 维护的区间有叶子节点被删除 if (cntv[o]) { sumv[o] += (LL) cntv[o] * tag; maxv[o] = tag; cntv[o] = 0; }}
Update
¶最后,更新操作就是将 待修改区间的权值比
1234567891011121314int __ul, __ur, __uv;void update(int o, int lft, int rht) { if (maxv[o] <= __uv) return; if (__ul<=lft and rht<=__ur) { clear(o, __uv); maintain(o, __uv); } else { int mid = mid(lft, rht); pushdown(o); if (__ul <= mid) update(lson); if (__ur > mid) update(rson); pushup(o); }}
Pushdown
¶需要注意的是,Pushdown 操作把 tag
信息下传后,当前节点的 tag
不应该置为
123456void pushdown(int o) { if (tagv[o]) { maintain(lc, tagv[o]); maintain(rc, tagv[o]); }}
复杂度分析
¶显然,单次 Update 和 Query 只会影响
空间复杂度
时间复杂度
尽管我们得到了
Related
¶