线段树维护区间(平方和,立方和)修改区间(加,赋值,乘)

题目地址

/*
* @Author: hannibal
* @Date:   2018-08-07 10:42:26
* @Last Modified by:   hannibal
* @Last Modified time: 2018-08-07 17:08:44
*/
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long  ll;
const ll mod = 10007;
const ll maxn = 1e5+10;
ll Case = 1, n, m;
struct node{
   
	ll l, r;
	ll add, mul, set;
	ll p1, p2, p3;
	ll mid(){
   return (l+r)/2;}
}tr[maxn<<2];
void pushup(ll rt) {
   
	tr[rt].p1 = (tr[rt<<1].p1 + tr[rt<<1|1].p1)%mod;
	tr[rt].p2 = (tr[rt<<1].p2 + tr[rt<<1|1].p2)%mod;
	tr[rt].p3 = (tr[rt<<1].p3 + tr[rt<<1|1].p3)%mod;
}
void caladd(ll rt) {
   
	ll len1 = (tr[rt<<1].r-tr[rt<<1].l+1)%mod;
	ll len2 =( tr[rt<<1|1].r-tr[rt<<1|1].l+1)%mod;
	tr[rt<<1].add = (tr[rt<<1].add+tr[rt].add%mod);tr[rt<<1|1].add = (tr[rt<<1|1].add+tr[rt].add)%mod;
	ll temp = (tr[rt].add*tr[rt].add%mod)*tr[rt].add%mod;
	tr[rt<<1].p3 =(tr[rt<<1].p3+(temp*len1)%mod+3*tr[rt].add*((tr[rt<<1].p2+tr[rt<<1].p1*tr[rt].add)%mod)%mod)%mod;
	tr[rt<<1|1].p3 = (tr[rt<<1|1].p3+(temp*len2)%mod+3*tr[rt].add*((tr[rt<<1|1].p2+tr[rt<<1|1].p1*tr[rt
  • 1
    点赞
  • 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、付费专栏及课程。

余额充值