[bzoj1798][Ahoi2009]Seq 维护序列seq ([洛谷P3373]【模板】线段树 2)

题目大意:有$n$个数,有$m$个操作,有三种:

  1. $1\;l\;r\;x:$把区间$[l,r]$内的数乘上$x$
  2. $2\;l\;r\;x:$把区间$[l,r]$内的数加上$x$
  3. $3\;l\;r:$询问区间$[l,r]$的和,对$p$取模

(线段树2就是先读入$n\;m\;p$,再读入序列;本题是先读入$n\;p$,读入序列,再读入$m$,双倍经验)

题解:线段树,把$lazy\_tag$变成两个,分别记录区间加和区间乘,注意乘法的优先级比加法高

卡点:无(我以前写的是什么代码啊?)



C++ Code:

#include <cstdio>
#define maxn 100010 << 2
long long V[maxn], cov[maxn], tg[maxn];
int n, m;
int s[maxn], L, R;
long long p, x;
void update(int rt) {
	V[rt] = (V[rt << 1] + V[rt << 1 | 1]) % p;
}
void build(int rt, int l, int r) {
	cov[rt] = 1;
	if (l == r) {
		V[rt] = s[l] % p;
		return ;
	}
	int mid = l + r >> 1;
	build(rt << 1, l, mid);
	build(rt << 1 | 1, mid + 1, r);
	update(rt);
}
void pushdown(int rt, long long len) {
	long long &Cov = cov[rt], &Tg = tg[rt];
	V[rt << 1] = (V[rt << 1] * Cov + Tg * (len + 1 >> 1)) % p;
	V[rt << 1 | 1] = (V[rt << 1 | 1] * Cov + Tg * (len >> 1)) % p;
	cov[rt << 1] = (cov[rt << 1] * Cov) % p;
	cov[rt << 1 | 1] = (cov[rt << 1 | 1] * Cov) % p;
	tg[rt << 1] = (tg[rt << 1] * Cov + Tg) % p;
	tg[rt << 1 | 1] = (tg[rt << 1 | 1] * Cov + Tg) % p;
	Cov = 1, Tg = 0;
}
void add1(int rt, int l, int r) {
	if (L <= l && R >= r) {
		V[rt] = (V[rt] * x) % p;
		cov[rt] = (cov[rt] * x) % p;
		tg[rt] = (tg[rt] * x) % p;
		return ;
	}
	int mid = l + r >> 1;
	if (cov[rt] != 1 || tg[rt]) pushdown(rt, r - l + 1);
	if (L <= mid) add1(rt << 1, l, mid);
	if (R > mid) add1(rt << 1 | 1, mid + 1, r);
	update(rt);
}
void add2(int rt, int l, int r) {
	if (L <= l && R >= r) {
		V[rt] = (V[rt] + x * (r - l + 1ll)) % p;
		tg[rt] = (tg[rt] + x) % p;
		return ;
	}
	int mid = l + r >> 1;
	if (cov[rt] != 1 || tg[rt]) pushdown(rt, r - l + 1);
	if (L <= mid) add2(rt << 1, l, mid);
	if (R > mid) add2(rt << 1 | 1, mid + 1, r);
	update(rt);
}
long long ask(int rt, int l, int r) {
	if (L <= l && R >= r) return V[rt] % p;
	int mid = l + r >> 1;
	long long ans = 0;
	if (cov[rt] != 1 || tg[rt]) pushdown(rt, r - l + 1);
	if (L <= mid) ans = ask(rt << 1, l, mid);
	if (R > mid) ans = (ans + ask(rt << 1 | 1, mid + 1, r)) % p;
	return ans;
}
int main() {
	scanf("%d%lld", &n, &p);
	for (int i = 1; i <= n; i++) scanf("%d", s + i);
	build(1, 1, n);
	scanf("%d", &m);
	while (m --> 0) {
		long long op;
		scanf("%lld%d%d", &op, &L, &R);
		switch (op) {
			case 1: {
				scanf("%lld", &x);
				add1(1, 1, n);
				break;
			}
			case 2: {
				scanf("%lld", &x);
				add2(1, 1, n);
				break;
			}
			default: printf("%lld\n", ask(1, 1, n));
		}
	}
	return 0;
} 

 

posted @ 2018-09-07 15:17  Memory_of_winter  阅读(150)  评论(0编辑  收藏  举报