小A的题 线段树区间赋值

小A的题
描述

由于小 A 实在是太菜了,因此他现在需要你的帮助: 现在小 A 手上有一个凌乱的 01 串,他想通过若干次对于这个 01 串的局部排序将它变成一个有趣的 01 序列。 现在有两种操作:

输入格式

l r 00 表示把区间 [l,r][给升序排序

l r 11 表示把区间 [l,r]给降序排序

然后小 A 这个菜鸡想知道在 m次操作之后序列长啥样。

输出格式

第一行一个 01 串 S。 第二行一个整数 m。 接下来 m 行每行三个整数 l,r,x,保证 l ≤ r     a n d    x = 0 l \le r \ \ \ and \ \ x=0 lr   and  x=0 中的一个。

m 次操作之后的 01 串

数据范围
∣ S ∣ ≤ 1000000 , m ≤ 500000 ∣ S ∣ ≤ 1000000 , m ≤ 500000 |S| \le 1000000,m \le 500000∣S∣≤1000000,m≤500000 S1000000,m500000S1000000,m500000

输出时每行末尾的多余空格,不影响答案正确性

样例输入
11001
1
2 4 0
样例输出
10011

因为区间只有01ÿ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是同时具有区间修改和区间赋值功能的线段树的实现: ```cpp #include <bits/stdc++.h> using namespace std; const int MAXN = 100005; int a[MAXN], sum[MAXN<<2], add[MAXN<<2], setv[MAXN<<2]; void pushup(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void pushdown(int rt, int ln, int rn) { if (setv[rt] != -1) { setv[rt<<1] = setv[rt<<1|1] = setv[rt]; add[rt<<1] = add[rt<<1|1] = 0; sum[rt<<1] = setv[rt] * ln; sum[rt<<1|1] = setv[rt] * rn; setv[rt] = -1; } if (add[rt]) { add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; sum[rt<<1] += add[rt] * ln; sum[rt<<1|1] += add[rt] * rn; add[rt] = 0; } } void build(int l, int r, int rt) { setv[rt] = -1; add[rt] = 0; if (l == r) { sum[rt] = a[l]; return; } int mid = (l + r) >> 1; build(l, mid, rt<<1); build(mid+1, r, rt<<1|1); pushup(rt); } void update_add(int L, int R, int C, int l, int r, int rt) { if (L <= l && r <= R) { add[rt] += C; sum[rt] += C * (r-l+1); return; } int mid = (l + r) >> 1; pushdown(rt, mid-l+1, r-mid); if (L <= mid) update_add(L, R, C, l, mid, rt<<1); if (R > mid) update_add(L, R, C, mid+1, r, rt<<1|1); pushup(rt); } void update_set(int L, int R, int C, int l, int r, int rt) { if (L <= l && r <= R) { setv[rt] = C; add[rt] = 0; sum[rt] = C * (r-l+1); return; } int mid = (l + r) >> 1; pushdown(rt, mid-l+1, r-mid); if (L <= mid) update_set(L, R, C, l, mid, rt<<1); if (R > mid) update_set(L, R, C, mid+1, r, rt<<1|1); pushup(rt); } int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return sum[rt]; } int mid = (l + r) >> 1; int ans = 0; pushdown(rt, mid-l+1, r-mid); if (L <= mid) ans += query(L, R, l, mid, rt<<1); if (R > mid) ans += query(L, R, mid+1, r, rt<<1|1); return ans; } int main() { int n, m; cin >> n >> m; for (int i = 1; i <= n; i++) { cin >> a[i]; } build(1, n, 1); while (m--) { int op, l, r, c; cin >> op >> l >> r >> c; if (op == 1) { update_add(l, r, c, 1, n, 1); } else if (op == 2) { update_set(l, r, c, 1, n, 1); } else { cout << query(l, r, 1, n, 1) << endl; } } return 0; } ``` 该线段树的主要思路是在普通线段树的基础上增加一个 `setv` 数组,表示当前区间是否被赋值。若 `setv[rt]` 不为 -1,则表示当前区间赋值为 `setv[rt]`,同时 `add[rt]` 被清空。若 `add[rt]` 不为 0,则表示当前区间被加上了 `add[rt]`,同时 `setv[rt]` 被清空。这样就能同时支持区间修改和区间赋值了。 需要注意的一点是,在进行区间赋值操作时,应当将左右儿子的 `add` 数组清空,因为此时区间被完全覆盖,之前的修改操作会被覆盖掉,没有意义了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值