_bzoj1798 [Ahoi2009]Seq 维护序列seq【线段树 lazy tag】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1798

注意,应保证当前节点维护的值是正确的,lazy tag只是一个下传标记,在下传时应即时更新儿子的维护值,在修改时也应即时更新当前节点的维护值。

#include <cstdio>

const int maxn = 100005;

int n, mod, a[maxn], m, t1, t2, t3, opr;
struct Node {
	int ql, qr;
	long long sm, mul, add;
} tree[maxn << 2];

inline void pushup(int p) {
	tree[p].sm = (tree[p << 1].sm + tree[p << 1 | 1].sm) % mod;
}
inline void pushdown(int p) {
	tree[p << 1].mul = tree[p << 1].mul * tree[p].mul % mod;
	tree[p << 1].add = (tree[p << 1].add * tree[p].mul + tree[p].add) % mod;
	tree[p << 1].sm = (tree[p << 1].sm * tree[p].mul + tree[p].add * (tree[p << 1].qr - tree[p << 1].ql + 1)) % mod;

	tree[p << 1 | 1].mul = tree[p << 1 | 1].mul * tree[p].mul % mod;
	tree[p << 1 | 1].add = (tree[p << 1 | 1].add * tree[p].mul + tree[p].add) % mod;
	tree[p << 1 | 1].sm = (tree[p << 1 | 1].sm * tree[p].mul + tree[p].add * (tree[p << 1 | 1].qr - tree[p << 1 | 1].ql + 1)) % mod;

	tree[p].mul = 1;
	tree[p].add = 0;
}
void make_tree(int p, int left, int right) {
	tree[p].ql = left;
	tree[p].qr = right;
	tree[p].mul = 1;
	if (left == right) {
		tree[p].sm = (long long)(a[left] % mod);
		return;
	}
	int mid = (left + right) >> 1;
	make_tree(p << 1, left, mid);
	make_tree(p << 1 | 1, mid + 1, right);
	pushup(p);
}
void mull(int p, int left, int right, int c) {
	if (tree[p].ql == left && tree[p].qr == right) {
		tree[p].mul = tree[p].mul * (long long)c % mod;
		tree[p].add = tree[p].add * (long long)c % mod;
		tree[p].sm = tree[p].sm * (long long)c % mod;
		return;
	}
	pushdown(p);
	int mid = (tree[p].ql + tree[p].qr) >> 1;
	if (right <= mid) {
		mull(p << 1, left, right, c);
	}
	else if (left > mid) {
		mull(p << 1 | 1, left, right, c);
	}
	else {
		mull(p << 1, left, mid, c);
		mull(p << 1 | 1, mid + 1, right, c);
	}
	pushup(p);
}
void addd(int p, int left, int right, int c) {
	if (tree[p].ql == left && tree[p].qr == right) {
		tree[p].add = (tree[p].add + (long long)c) % mod;
		tree[p].sm = (tree[p].sm + (long long)c * (long long)(tree[p].qr - tree[p].ql + 1)) % mod;
		return;
	}
	pushdown(p);
	int mid = (tree[p].ql + tree[p].qr) >> 1;
	if (right <= mid) {
		addd(p << 1, left, right, c);
	}
	else if (left > mid) {
		addd(p << 1 | 1, left, right, c);
	}
	else {
		addd(p << 1, left, mid, c);
		addd(p << 1 | 1, mid + 1, right, c);
	}
	pushup(p);
}
int qry(int p, int left, int right) {
	if (tree[p].ql == left && tree[p].qr == right) {
		return (int)tree[p].sm;
	}
	pushdown(p);
	int mid = (tree[p].ql + tree[p].qr) >> 1, rt;
	if (right <= mid) {
		rt = qry(p << 1, left, right);
	}
	else if (left > mid) {
		rt = qry(p << 1 | 1, left, right);
	}
	else {
		rt = qry(p << 1, left, mid);
		rt = (rt + qry(p << 1 | 1, mid + 1, right)) % mod;
	}
	pushup(p);
	return rt;
}

int main(void) {
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	scanf("%d%d", &n, &mod);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", a + i);
	}
	make_tree(1, 1, n);
	scanf("%d", &m);
	while (m--) {
		scanf("%d%d%d", &opr, &t1, &t2);
		if (opr == 1) {
			scanf("%d", &t3);
			mull(1, t1, t2, t3);
		}
		else if (opr == 2) {
			scanf("%d", &t3);
			addd(1, t1, t2, t3);
		}
		else {
			printf("%d\n", qry(1, t1, t2));
		}
	}
	return 0;
}

  

时间: 2024-07-28 17:20:15

_bzoj1798 [Ahoi2009]Seq 维护序列seq【线段树 lazy tag】的相关文章

bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1798 Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树多重标记下传)

www.cnblogs.com/shaokele/ bzoj1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,-,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值

1798: [Ahoi2009]Seq 维护序列seq

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 5886  Solved: 2087[Submit][Status][Discuss] Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和

bzoj1798[Ahoi2009]Seq 维护序列seq

bzoj1798[Ahoi2009]Seq 维护序列seq 题意: 维护序列,支持区间加.区间乘.区间求和模一个数.序列大小和操作数≤100000 题解: 线段树,加标记和乘标记的处理同bzoj4003.模的时候注意细节. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define m

bzoj1798: [Ahoi2009]Seq 维护序列seq 2011-12-20

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MB Submit: 497  Solved: 203 [Submit][Status][Discuss] Description 老 师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的

bzoj 1798 [Ahoi2009]Seq 维护序列seq(线段树+传标)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1798 [题意] 给定一个序列,要求提供区间乘/加,以及区间求和的操作 [思路] 线段树+传标. 下传标记的方式可以类比这里 click here [代码] 1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio>

bzoj1798: [Ahoi2009]Seq 维护序列seq(线段树)

bzoj1798 题目描述:给定n个数的序列,有三种操作. ?????1.将一段区间乘上c ?????2.将一段区间加上c ?????3.求一段区间的和 输入格式:第一行两个整数第一行两个整数N和P(1≤P≤1000000000).第二行含有N个非负整数,从左到右依次为a1,a2,-,aN, (0≤ai≤1000000000,1≤i≤N).第三行有一个整数M,表示操作总数.从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:"1 t g c"(不含双引号).表示把所有满足

bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树

题目传送门 这道题就是线段树 先传乘法标记再传加法 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=400010; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}

BZOJ 1798 [Ahoi2009]Seq 维护序列seq 线段树

题意:链接 方法:线段树 解析: 俩标记sb题 更新乘的时候更新加 完了 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define N 100010 using namespace std; typedef