线段树基本操作

区间修改板子1

只有一种操作,即在区间内每个数的加上k

题目是P3372 【模板】线段树 1

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long  ll;
const int maxn = 200000;
struct MyStruct {
    ll sum, lazy;
}tree[maxn << 2];
ll n, m;
ll a[maxn];
void pushup(ll rt) {
    tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
}
void build(ll l, ll r, ll rt) {
    if (l == r) {
        //scanf("%lld", &tree[rt].sum);
        tree[rt].sum = a[l];
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup(rt);
}
void ferr(ll add, ll l, ll r, ll rt) {
    tree[rt].lazy += add;
    tree[rt].sum += add * (r - l + 1);
}
void pushdown(ll l, ll r, ll rt) {
    ll m = (l + r) >> 1;
    ferr(tree[rt].lazy, lson);
    ferr(tree[rt].lazy, rson);
    tree[rt].lazy = 0;
}
void update(ll add,ll L,ll R,ll l,ll r,ll rt) {
    if (L <= l && r <= R) {
        ferr(add, l, r, rt);
        return;
    }
    pushdown(l, r, rt);
    ll m = (l + r) >> 1;
    if (L <= m) update(add, L, R, lson);
    if (R > m) update(add, L, R, rson);
    pushup(rt);
}
ll query(ll L, ll R, ll l, ll r, ll rt) {
    ll res = 0;
    if (L <= l && r <= R) {
        return tree[rt].sum;
    }
    ll m = (l + r) >> 1;
    pushdown(l, r, rt);
    if (L <= m) res += query(L, R, lson);
    if (R > m) res += query(L, R, rson);
    return res;
}
int main() {
    int x, y, c, k;
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%lld",&a[i]);
    }
    build(1, n, 1);
    for (int i = 1; i <= m; i++) {
        scanf("%d", &c);
        if (c == 1) {
            scanf("%d%d%d", &x, &y, &k);
            update(k, x, y, 1, n, 1);
        }
        else {
            scanf("%d%d", &x, &y);
            printf("%lld\n", query(x, y, 1, n, 1));
        }
    }
    return 0;
}

区间修改板子2 有两种操作,在区间内同时加一个数与同时乘一个数

题目是P3373 【模板】线段树 2

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 5;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lc rt<<1
#define rc rt<<1|1
struct MyStruct{
	ll sum, add,mul;
}tree[maxn<<2];
ll n, k, a[maxn];
int p;
//void pushup(ll rt) {
//	tree[rt].sum = tree[lc].sum + tree[rc].sum;
//	tree[rt].sum %= p;
//}
void build(ll l, ll r, ll rt) {
	tree[rt].add = 0;
	tree[rt].mul = 1;
	if (l == r) {
		tree[rt].sum = a[l];
	}
	else {
		ll m = (l + r) >> 1;
		build(lson);
		build(rson);
		tree[rt].sum = tree[lc].sum + tree[rc].sum;
	}
	tree[rt].sum %= p;
	return;
}
void pushdown(ll l, ll r, ll rt) {
	ll m = (l + r) >> 1;
	tree[rt*2].sum=(tree[rt*2].sum*tree[rt].mul+tree[rt].add*(m-l+1))%p;
    tree[rt*2+1].sum=(tree[rt*2+1].sum*tree[rt].mul+tree[rt].add*(r-m))%p;
//很好维护的lazytag
    tree[rt*2].mul=(tree[rt*2].mul*tree[rt].mul)%p;
    tree[rt*2+1].mul=(tree[rt*2+1].mul*tree[rt].mul)%p;
    tree[rt*2].add=(tree[rt*2].add*tree[rt].mul+tree[rt].add)%p;
    tree[rt*2+1].add=(tree[rt*2+1].add*tree[rt].mul+tree[rt].add)%p;
	
	tree[rt].mul=1;
	tree[rt].add=0;
}
void ud1(ll mul, int L, int R, int l, int r, int rt){
//假如本区间和给出的区间没有交集
    if(R<l || r<L){
        return ;
    }
//假如给出的区间包含本区间
    if(L<=l && r<=R){
		tree[rt].sum = (tree[rt].sum*mul) % p;
		tree[rt].mul = (tree[rt].mul*mul) % p;
		tree[rt].add = (tree[rt].add*mul) % p;
        return ;
    }
//假如给出的区间和本区间有交集,但是也有不交叉的部分
//先传递lazytag
	pushdown(l, r, rt);
	int m = (l + r) >> 1;
	ud1(mul, L, R, lson);
	ud1(mul, L, R, rson);
	tree[rt].sum = (tree[rt * 2].sum + tree[rt * 2 + 1].sum) % p;
    return ;
}
void ud2(ll add,ll L,ll R,ll l,ll r,ll rt){
    if(R<l || r<L){
        return ;
    }
    if(L<=l && r<=R){
        tree[rt].add=(tree[rt].add+add)%p;
        tree[rt].sum=(tree[rt].sum+add*(r-l+1))%p;
        return ;
    }
	pushdown(l, r, rt);
	ll m = (l + r) >> 1;
	ud2(add, L, R, lson);
	ud2(add, L, R, rson);
	tree[rt].sum = (tree[rt * 2].sum + tree[rt * 2 + 1].sum) % p;
    return ;
}

ll query(ll L, ll R, ll l, ll r, ll rt) {
	if (L > r|| R < l) return 0;
	if (L <= l && r <= R) {
		return tree[rt].sum;
	}
	pushdown(l, r, rt);
	ll res = 0, m = (l + r) >> 1;
	return (query(L, R, lson) + query(L, R, rson)) % p;

}
int main(){
	ios::sync_with_stdio(false);
	cin >> n >> k >> p;
	for (int i = 1; i <= n; i++) cin >> a[i];
	build(1, n, 1);
	while (k--) {
		ll x, y, z, k;
		cin >> z;
		if (z == 1) {
			cin >> x >> y >> k;
			ud1(k, x, y, 1, n, 1);
		}
		else if (z == 2) { 
			cin >> x >> y >> k;
			ud2(k, x, y, 1, n, 1);
		}
		else {
			cin >> x >> y;
			cout << query(x, y, 1, n, 1) << endl;
		}
	}
	
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对算法有兴趣的可以来看看 在自然数,且所有的数不大于30000的范围内讨论一个问题:现在已知n条线段,把端点依次输入告诉你,然后有m个询问,每个询问输入一个点,要求这个点在多少条线段上出现过; 最基本的解法当然就是读一个点,就把所有线段比一下,看看在不在线段中; 每次询问都要把n条线段查一次,那么m次询问,就要运算m*n次,复杂度就是O(m*n) 这道题m和n都是30000,那么计算量达到了10^9;而计算机1秒的计算量大约是10^8的数量级,所以这种方法无论怎么优化都是超时 因为n条线段是固定的,所以某种程度上说每次都把n条线段查一遍有大量的重复和浪费; 线段树就是可以解决这类问题的数据结构 举例说明:已知线段[2,5] [4,6] [0,7];求点2,4,7分别出现了多少次 在[0,7]区间上建立一棵满二叉树:(为了和已知线段区别,用【】表示线段树中的线段) 【0,7】 / \ 【0,3】 【4,7】 / \ / \ 【0,1】 【2,3】 【4,5】 【6,7】 / \ / \ / \ / \ 【0,0】 【1,1】 【2,2】 【3,3】 【4,4】 【5,5】 【6,6】 【7,7】 每个节点用结构体: struct line { int left,right; // 左端点、右端点 int n; // 记录这条线段出现了多少次,默认为0 }a[16]; 和堆类似,满二叉树的性质决定a[i]的左儿子是a[2*i]、右儿子是a[2*i+1]; 然后对于已知的线段依次进行插入操作: 从树根开始调用递归函数insert // 要插入的线段的左端点和右端点、以及当前线段树中的某条线段 void insert(int s,int t,int step)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值