HYSBZ 1798(Ahoi2009) Seq 维护序列seq(区间更新+加法乘法混合操作)
1798: [Ahoi2009]Seq 维护序列seq
Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 9612 Solved: 3560
[Submit][Status][Discuss]
Description
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式:
(1)把数列中的一段数全部乘一个值;
(2)把数列中的一段数全部加一个值;
(3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
Input
第一行两个整数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)。
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
Output
对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
Sample Input
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
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
Sample Output
2
35
8
35
8
HINT
【样例说明】
初始时数列为(1,2,3,4,5,6,7)。
经过第1次操作后,数列为(1,10,15,20,25,6,7)。
对第2次操作,和为10+15+20=45,模43的结果是2。
经过第3次操作后,数列为(1,10,24,29,34,15,16}
对第4次操作,和为1+10+24=35,模43的结果是35。
对第5次操作,和为29+34+15+16=94,模43的结果是8。
测试数据规模如下表所示
数据编号 1 2 3 4 5 6 7 8 9 10
N= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000
M= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000
思路:线段树,注意两种操作不能简单的只往下传标记。每次传乘法标记时,要把加法标记同时乘上乘法标记,
例如(A+B)*C,那么对应我们知道结果等同于A*C+B*C,那么我们在打lazy Tag的时候,如果对于当前区间有加法的部分,那么对应我们将这个加法部分乘上C。乘法部分的Lazy直接累乘上去即可。
例如(A+B)*C,那么对应我们知道结果等同于A*C+B*C,那么我们在打lazy Tag的时候,如果对于当前区间有加法的部分,那么对应我们将这个加法部分乘上C。乘法部分的Lazy直接累乘上去即可。
代码:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <string>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>
#define Fbo friend bool operator < (node a, node b)
#define mem(a, b) memset(a, b, sizeof(a))
#define FOR(a, b, c) for (int a = b; a <= c; a++)
#define RFOR(a, b, c) for (int a = b; a >= c; a--)
#define off ios::sync_with_stdio(0)
#define sc(a) scanf("%lld",&a)
#define pr(a) printf("%lld\n",a);
#define SC(n,m) scanf("%lld%lld",&n,&m)
bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; }
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;//1e10
const int mod = 1e9 + 7;
const int Maxn = 2e5 + 9;
const int M = Maxn * 20;
const double pi = acos(-1.0);
const double eps = 1e-8;
ll a[Maxn],n,p,m,c,xx,x,y;
struct node {
ll l, r;//区间[l,r]
ll add;//区间加法
ll sum;//区间和
ll mul;//区间乘
}tree[Maxn * 4 + 5];//一定要开到4倍多的空间
void pushup(ll rt) { //向上更新
tree[rt].sum = (tree[rt << 1].sum + tree[rt << 1 | 1].sum) % p;
}
void pushdown(ll rt) {//向下更新
//if (tree[rt].add && tree[rt].mul == 0) { //若有标记,则讲标记向下移动一层
tree[rt << 1].add = (tree[rt<<1].add * tree[rt].mul + tree[rt].add) % p;
tree[rt << 1 | 1].add = (tree[rt << 1 | 1].add * tree[rt].mul + tree[rt].add) % p;
tree[rt << 1].mul = (tree[rt << 1].mul * tree[rt].mul) % p;
tree[rt << 1 | 1].mul = (tree[rt << 1 | 1].mul * tree[rt].mul) % p;
tree[rt << 1].sum = (tree[rt << 1].sum * tree[rt].mul + (tree[rt << 1].r - tree[rt << 1].l + 1) * tree[rt].add) % p;
tree[rt << 1 | 1].sum = (tree[rt << 1 | 1].sum * tree[rt].mul + (tree[rt << 1 | 1].r - tree[rt << 1 | 1].l + 1) * tree[rt].add) % p;
tree[rt].add = 0; //取消本层标记
tree[rt].mul = 1;
// }
}
void BuildTree(ll l, ll r, ll rt) {
tree[rt].l = l;
tree[rt].r = r;
tree[rt].add = 0;
tree[rt].mul = 1;
//tree[rt].sum = r - l + 1; //更新结点rt的值
if (l == r) {
//此行根据题意看情况填什么————-
tree[rt].sum = a[l];
//————————————————
return;
}
ll mid = (l + r) >> 1;
BuildTree(l, mid, rt << 1); //递归左子树
BuildTree(mid + 1, r, (rt << 1) + 1); //递归右子树
pushup(rt);//向上更新
}
void updata(ll l, ll r, ll val, ll rt) { //root为结点 区间更新
// cout << l << " " << tree[rt].l << "----" << r << " " << tree[rt].r << endl; // 验证路径
if (tree[rt].l >= l && tree[rt].r <= r) {
if (xx == 1) {
tree[rt].add = (tree[rt].add * val) % p;
tree[rt].mul = (tree[rt].mul * val) % p;
tree[rt].sum = (tree[rt].sum * val) % p;
return;
}
else if (xx == 2) {
tree[rt].add = (tree[rt].add + val) % p;
tree[rt].sum = (tree[rt].sum + (ll)(tree[rt].r - tree[rt].l + 1) * val)%p;
return;
}
}
pushdown(rt);
ll mid = (tree[rt].l + tree[rt].r) >> 1;
if (l <= mid) {
updata(l, r, val,rt << 1);
}
if (r > mid) {
updata(l, r, val,rt << 1 | 1);
}
pushup(rt);//向上更新
}
ll querySum(ll l, ll r, ll rt) { //区间求和
if (l <= tree[rt].l && r >= tree[rt].r) {
return tree[rt].sum%p;
}
pushdown(rt);
ll mid = (tree[rt].l + tree[rt].r) >> 1;
ll ans = 0;
if (l <= mid) {
ans += querySum(l, r, rt << 1);
}
if (r > mid) {
ans += querySum(l, r, rt << 1 | 1);
}
return ans%p;
}
int main() {
SC(n, p);
FOR(i, 1, n)sc(a[i]);
BuildTree(1, n, 1);
sc(m);
while (m--) {
sc(xx);
if (xx == 1) {
sc(x), sc(y), sc(c);
updata(x, y, c, 1);
}
else if (xx == 2) {
sc(x), sc(y), sc(c);
updata(x, y, c, 1);
}
else if (xx == 3) {
sc(x), sc(y);
pr(querySum(x, y, 1));
}
}
return 0;
}

浙公网安备 33010602011771号