【ybt高效进阶4-4-4】【luogu P2023】维护序列

维护序列

题目链接:ybt高效进阶4-4-4 / luogu P2023

题目大意

给你一个序列,要你维护三个操作。
把一个区间的数乘一个值或加一个值,还有区间求和。

思路

主要也是用 lazy 标记。

因为有乘法和加法,我们如果给乘法打标记的时候出了乘上原来的数,还要把加法的懒标记也乘上。
然后下传懒标记的时候先下传乘法,再下传加法。

而且下传乘法的时候跟上面一样,也要把下面的加法懒标记也乘上。

然后其他就是基本的线段树了。

代码

#include<cstdio>
#define ll long long

using namespace std;

struct Tree {
    
    
	ll x, lazya, lazyt;
}tree[800001];
int n, a[100001], m;
int op, x, y, z;
ll mo;

void up(int now) {
    
    
	tree[now].x = (tree[now << 1].x + tree[now << 1 | 1].x) % mo;
}

void down(int now, int l, int r) {
    
    
	//先处理乘,再处理加
	tree[now << 1].lazyt = (tree[now << 1].lazyt * tree[now].lazyt) % mo;
	tree[now << 1].lazya = (tree[now << 1].lazya * tree[now].lazyt) % mo;
	tree[now << 1].x = (tree[now << 1].x * tree[now].lazyt) % mo;
	tree[now << 1 | 1].lazyt = (tree[now << 1 | 1].lazyt * tree[now].lazyt) % mo;
	tree[now << 1 | 1].lazya = (tree[now << 1 | 1].lazya * tree[now].lazyt) % mo;
	tree[now << 1 | 1].x = (tree[now << 1 | 1].x * tree[now].lazyt) % mo;
	tree[now].lazyt = 1;
	
	int mid = (l + r) >> 1;
	tree[now << 1].lazya = (tree[now << 1].lazya + tree[now].lazya) % mo;
	tree[now << 1].x = (tree[now << 1].x + tree[now].lazya * (mid - l + 1) % mo) % mo;
	tree[now << 1 | 1].lazya = (tree[now << 1 | 1].lazya + tree[now].lazya) % mo;
	tree[now << 1 | 1].x = (tree[now << 1 | 1].x + tree[now].lazya * (r - (mid + 1) + 1) % mo) % mo;
	tree[now].lazya = 0;
}

void build(int now, int l, int r) {
    
    
	tree[now].lazyt = 1;
	
	if (l == r) {
    
    
		tree[now].x = a[l] % mo;
		return ;
	}
	
	int mid = (l + r) >> 1;
	build(now << 1, l, mid);
	build(now << 1 | 1, mid + 1, r);
	
	up(now);
}

void times_num(int now, int l, int r, int L, int R, int timesnum) {
    
    
	if (L <= l && r <= R) {
    
    
		tree[now].x = (tree[now].x * timesnum) % mo;
		tree[now].lazya = (tree[now].lazya * timesnum) % mo;//记得加也要乘上(因为你 lazyt 是不会管这里的,这里的就一定要全部都乘)
		tree[now].lazyt = (tree[now].lazyt * timesnum) % mo;
		return ;
	}
	
	down(now, l, r);
	
	int mid = (l + r) >> 1;
	if (L <= mid) times_num(now << 1, l, mid, L, R, timesnum);
	if (mid + 1 <= R) times_num(now << 1 | 1, mid + 1, r, L, R, timesnum);
	
	up(now);
}

void add_num(int now, int l, int r, int L, int R, int addnum) {
    
    
	if (L <= l && r <= R) {
    
    
		tree[now].x = (tree[now].x + addnum * (r - l + 1) % mo) % mo;
		tree[now].lazya = (tree[now].lazya + addnum) % mo;
		return ;
	}
	
	down(now, l, r);
	
	int mid = (l + r) >> 1;
	if (L <= mid) add_num(now << 1, l, mid, L, R, addnum);
	if (mid + 1 <= R) add_num(now << 1 | 1, mid + 1, r, L, R, addnum);
	
	up(now);
}

ll get_sum(int now, int l, int r, int L, int R) {
    
    
	if (L <= l && r <= R) {
    
    
		return tree[now].x;
	}
	
	down(now, l, r);
	
	int mid = (l + r) >> 1;
	ll re = 0;
	if (L <= mid) re = (re + get_sum(now << 1, l, mid, L, R)) % mo;
	if (mid + 1 <= R) re = (re + get_sum(now << 1 | 1, mid + 1, r, L, R)) % mo;
	return re;
}

int main() {
    
    
	scanf("%d %lld", &n, &mo);
	
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	build(1, 1, n);
	
	scanf("%d", &m);
	while (m--) {
    
    
		scanf("%d", &op);
		if (op == 1) {
    
    
			scanf("%d %d %d", &x, &y, &z);
			times_num(1, 1, n, x, y, z);
		}
		else if (op == 2) {
    
    
			scanf("%d %d %d", &x, &y, &z);
			add_num(1, 1, n, x, y, z);
		}
		else {
    
    
			scanf("%d %d", &x, &y);
			printf("%lld\n", get_sum(1, 1, n, x, y));
		}
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/115278355
今日推荐