[BZOJ1798][Ahoi2009]Seq 维护序列seq

[BZOJ1798][Ahoi2009]Seq 维护序列seq

试题描述

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。

输入

第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

输出

对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

输入示例

7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7

输出示例

2
35
8

数据规模及约定

N ≤ 100000, M ≤ 100000

题解

线段树,打标记恶心一些。因为有乘法分配律,所以在乘法懒标记下传时把加法的懒标记也乘一下,加法懒标记还是该怎么打怎么打。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
    if(Head == Tail) {
        int l = fread(buffer, 1, BufferSize, stdin);
        Tail = (Head = buffer) + l;
    }
    return *Head++;
}
int read() {
    int x = 0, f = 1; char c = Getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
    return x * f;
}

#define maxn 100010
#define LL long long
int n, val[maxn];
LL MOD, sumv[maxn<<2], addv[maxn<<2], timv[maxn<<2];

void maintain(int L, int R, int o) {
	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
	if(L == R) return ;
	sumv[o] = ((sumv[lc] * timv[lc] % MOD + addv[lc] * (LL)(M - L + 1) % MOD) % MOD + (sumv[rc] * timv[rc] % MOD + addv[rc] * (LL)(R - M) % MOD) % MOD) % MOD;
	return ;
}
void build(int L, int R, int o) {
	timv[o] = 1;
	if(L == R) sumv[o] = val[L];
	else {
		int M = L + R >> 1, lc = o << 1, rc = lc | 1;
		build(L, M, lc); build(M+1, R, rc);
		maintain(L, R, o);
	}
	return ;
}
void pushdown(int L, int R, int o) {
	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
	LL len = (LL)(R - L + 1);
	if(timv[o] != 1) {
		(sumv[o] *= timv[o]) %= MOD;
		if(L != R) {
			(timv[lc] *= timv[o]) %= MOD; (addv[lc] *= timv[o]) %= MOD;
			(timv[rc] *= timv[o]) %= MOD; (addv[rc] *= timv[o]) %= MOD;
		}
		timv[o] = 1;
	}
	if(addv[o]) {
		sumv[o] += (addv[o] * len % MOD); if(sumv[o] >= MOD) sumv[o] -= MOD;
		if(L != R) {
			addv[lc] += addv[o]; if(addv[lc] >= MOD) addv[lc] -= MOD;
			addv[rc] += addv[o]; if(addv[rc] >= MOD) addv[rc] -= MOD;
		}
		addv[o] = 0;
	}
	return ;
}
void update1(int L, int R, int o, int ql, int qr, LL v) {
	pushdown(L, R, o);
	if(ql <= L && R <= qr) (timv[o] *= v) %= MOD, (addv[o] *= v) %= MOD;
	else {
		int M = L + R >> 1, lc = o << 1, rc = lc | 1;
		if(ql <= M) update1(L, M, lc, ql, qr, v);
		if(qr > M) update1(M+1, R, rc, ql, qr, v);
	}
	maintain(L, R, o);
	return ;
}
void update2(int L, int R, int o, int ql, int qr, LL v) {
	pushdown(L, R, o);
	if(ql <= L && R <= qr){ addv[o] += v; if(addv[o] >= MOD) addv[o] -= MOD; }
	else {
		int M = L + R >> 1, lc = o << 1, rc = lc | 1;
		if(ql <= M) update2(L, M, lc, ql, qr, v);
		if(qr > M) update2(M+1, R, rc, ql, qr, v);
	}
	maintain(L, R, o);
	return ;
}
LL query(int L, int R, int o, int ql, int qr) {
	pushdown(L, R, o);
	if(ql <= L && R <= qr) return (sumv[o] * timv[o] % MOD + addv[o] * (LL)(R - L + 1) % MOD) % MOD;
	int M = L + R >> 1, lc = o << 1, rc = lc | 1;
	LL ans = 0;
	if(ql <= M){ ans += query(L, M, lc, ql, qr); if(ans >= MOD) ans -= MOD; }
	if(qr > M){ ans += query(M+1, R, rc, ql, qr); if(ans >= MOD) ans -= MOD; }
	return ans;
}

int main() {
	n = read(); MOD = read();
	for(int i = 1; i <= n; i++) val[i] = read() % MOD;
	
	build(1, n, 1);
	int q = read();
	while(q--) {
		int tp = read(), ql = read(), qr = read(), v;
		if(tp == 1) {
			v = read() % MOD;
			update1(1, n, 1, ql, qr, v);
		}
		if(tp == 2) {
			v = read() % MOD;
			update2(1, n, 1, ql, qr, v);
		}
		if(tp == 3) printf("%lld\n", query(1, n, 1, ql, qr));
	}
	
	return 0;
}

 

posted @ 2016-08-05 18:05  xjr01  阅读(208)  评论(0编辑  收藏  举报