ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-03-28 11:59:45  阅读:237  来源: 互联网

标签:lazyt return 进阶 P2023 int luogu mo tree now


维护序列

题目链接: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;
}

标签:lazyt,return,进阶,P2023,int,luogu,mo,tree,now
来源: https://blog.csdn.net/weixin_43346722/article/details/115278355

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有