hdu5306 Gorgeous Sequence(线段树:复杂区间更新)
来源:互联网 发布:快递员扫码发短信软件 编辑:程序博客网 时间:2024/06/07 22:35
题目:
三种操作0 l r t: 使这个区间的每个值变成min(t,a[i])。 1 l r: 输出区间最大值 2 l r: 输出区间和(1 <= n,m <= 1e6, 0 <= ai,t <= 2^31)
分析:
1和2操作很简单,0操作很难,一个一个改时间肯定不允许,但是又没什么办法可以直接全改掉。
结合题目问的是区间最大值和区间和,那么就思考操作 0 会对区间最大值和区间和有什么影响,于是就有了以下方法:
维护 3 个值,区间最大值,区间严格次大值,区间最大值的个数。然后我们每次做0操作的时候,就会有3种情况。
- t >= 区间最大值, 这时每个值都不用修改,直接返回。
- 区间次大值 < t < 区间最大值,此时只有最大值会变,又已经求得了最大值的个数,所以我们可以直接更新这段的sum和max。
- 其他情况。无法直接对当前情况修改,所以继续搜两个儿子,直到搜到前两种情况为止。
我们可以把区间的最大值看做是这个区间的标记,因为每次更新的时候只会更新到(区间次大值 < t < 区间最大值)的情况,然后会修改sum和max,所以以后一旦进入这个区间的子树,必须先更新这个子树的max和sum。于是就有了pushdown()的写法,它就是负责把当前区间的sum和mx信息传给子树。
代码
#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <vector>#include <set>#include <cmath>#include <cstdlib>#include <cstring>#include <cstdio>using namespace std;#define ms(a,b) memset(a,b,sizeof(a))#define lson rt*2,l,(l+r)/2#define rson rt*2+1,(l+r)/2+1,rtypedef long long ll;const int MAXN = 1e6 + 10;const double EPS = 1e-8;const int INF = 0x3f3f3f3f;ll sum[MAXN << 2], mx[MAXN << 2], se[MAXN << 2], num[MAXN << 2];int n, m;void pushup(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]); if (mx[rt << 1] == mx[rt << 1 | 1]) { se[rt] = max(se[rt << 1], se[rt << 1 | 1]); num[rt] = num[rt << 1] + num[rt << 1 | 1]; } else { //这个地方需要特别注意!因为一个子树的次大值有可能比另一个子树的最大值还要大。所以总的次大值不一定是哪个,需要都比较一下。debug了很久很久。。。 se[rt] = max(se[rt<<1],se[rt<<1|1]); se[rt] = max(se[rt],min(mx[rt << 1], mx[rt << 1 | 1])); num[rt] = mx[rt << 1] > mx[rt << 1 | 1] ? num[rt << 1] : num[rt << 1 | 1]; }}void build(int rt, int l, int r) { if (l == r) { scanf("%lld", &sum[rt]); mx[rt] = sum[rt]; se[rt] = -1; num[rt] = 1; return; } build(lson); build(rson); pushup(rt);}void putTag(int rt, int x) { if (x >= mx[rt]) return; sum[rt] -= num[rt] * (mx[rt] - x); mx[rt] = x;}void pushdown(int rt) { putTag(rt << 1, mx[rt]); putTag(rt << 1 | 1, mx[rt]);}void change(int L, int R, int rt, int l, int r, int x) { if (x >= mx[rt]) return; if (L <= l && R >= r && se[rt] < x) { putTag(rt, x); return; } pushdown(rt); if (L <= (l + r) / 2) change(L, R, lson, x); if (R > (l + r) / 2) change(L, R, rson, x); pushup(rt);}int queryMax(int L, int R, int rt, int l, int r) { if (L <= l && R >= r) { return mx[rt]; } pushdown(rt); int ans = 0; if (L <= (l + r) / 2) ans = queryMax(L, R, lson); if (R > (l + r) / 2) ans = max(ans, queryMax(L, R, rson)); return ans;}ll querySum(int L, int R, int rt, int l, int r) { if (L <= l && R >= r) { return sum[rt]; } pushdown(rt); ll ans = 0; if (L <= (l + r) / 2) ans += querySum(L, R, lson); if (R > (l + r) / 2) ans += querySum(L, R, rson); return ans;}int main() { int T; scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); build(1, 1, n); while (m--) { int op, L, R, t; scanf("%d%d%d", &op, &L, &R); if (op == 0) {scanf("%d", &t); change(L, R, 1, 1, n, t);} else if (op == 1) printf("%d\n", queryMax(L, R, 1, 1, n)); else printf("%lld\n", querySum(L, R, 1, 1, n)); } } return 0;}
阅读全文
0 0
- hdu5306 Gorgeous Sequence(线段树:复杂区间更新)
- hdu5306 Gorgeous Sequence
- [题解]hdu5306 Gorgeous Sequence
- hdu 5306 Gorgeous Sequence(线段树)
- HDU 5306 Gorgeous Sequence(线段树)
- [线段树 区间最值操作] HDU 5306 Gorgeous Sequence
- HDOJ 5306 Gorgeous Sequence 线段树
- HDU 5306 Gorgeous Sequence(线段树)
- HDU 5306 Gorgeous Sequence 线段树
- [HDU] 5306 Gorgeous Sequence [区间取min&求和&求max][线段树]
- UESTC 94 Bracket Sequence(线段树的区间更新)
- [HDU5306]吉司机线段树
- codeforces 283A. Cows and Sequence [线段树-区间更新]
- HDOJ--4893--Wow! Such Sequence!【线段树+单点、区间更新】
- HDU 5828-H - Rikka with Sequence-线段树+玄学-区间开方/区间更新/区间求和
- hdu 4893 Wow! Such Sequence! 线段树单点更新+区间更新+区间查询
- HDU 4893 Wow! Such Sequence! (线段树单点更新+区间更新+区间查询+二分)
- Gorgeous Sequence
- linux 创建连接命令 ln -s 软链接
- OpenGL 02 OpenGL缓存数据
- 2.Android硬件访问服务编写系统代码
- Codeforces Round #422 (Div. 2) E. Liar 贪心 dp 后缀数组
- tomcat添加为linux服务
- hdu5306 Gorgeous Sequence(线段树:复杂区间更新)
- mysql创建远程用户并授权
- SQL学习
- 什么是数据库,什么是SQL,什么是MySQL
- Spring-Bean的作用域
- C#学习过程中vs使用和代码编辑技巧总结
- HAUToj 1284: SP教数学 (线段树+矩阵快速幂
- linux下如何查看python位数
- Memcache的使用(c#)