维护序列-线段树终极模板懒标记

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。有长为 NN

的数列,不妨设为 a1,a2,…,aNa1,a2,…,aN

。有如下三种操作形式:把数列中的一段数全部乘一个值;把数列中的一段数全部加一个值;询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 PP

的值。输入格式第一行两个整数 NN

和 PP

;第二行含有 NN

个非负整数,从左到右依次为 a1,a2,…,aNa1,a2,…,aN

;第三行有一个整数 MM

,表示操作总数;从第四行开始每行描述一个操作,输入的操作有以下三种形式:操作 11

:1 t g c,表示把所有满足 t≤i≤gt≤i≤g

的 aiai

改为 ai×cai×c

;操作 22

:2 t g c,表示把所有满足 t≤i≤gt≤i≤g

的 aiai

改为 ai+cai+c

;操作 33

:3 t g,询问所有满足 t≤i≤gt≤i≤g

的 aiai

的和模 PP

的值。同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。输出格式对每个操作 33

,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。数据范围1≤N,M≤1051≤N,M≤105

,
1≤t≤g≤N1≤t≤g≤N

,
0≤c,ai≤1090≤c,ai≤109

,
1≤P≤1091≤P≤109

输入样例: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
样例解释初始时数列为 {1,2,3,4,5,6,7}{1,2,3,4,5,6,7}

;经过第 11

次操作后,数列为 {1,10,15,20,25,6,7}{1,10,15,20,25,6,7}

;对第 22

次操作,和为 10+15+20=4510+15+20=45

,模 4343

的结果是 22

;经过第 33

次操作后,数列为 {1,10,24,29,34,15,16}{1,10,24,29,34,15,16}

;对第 44

次操作,和为 1+10+24=351+10+24=35

,模 4343

的结果是 3535

;对第 55

次操作,和为 29+34+15+16=9429+34+15+16=94

,模 4343

的结果是 88

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=100010;
int n,m,p;
int w[N];
struct Node{
 int l,r;
 int sum,add,mul;
}tr[N*4];
void pushup(int u){
 tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%p;
}
void eval(Node &t,int add,int mul){
 t.sum=((LL)t.sum*mul+(LL)(t.r-t.l+1)*add)%p;
 t.mul=((LL)t.mul*mul)%p;
 t.add=((LL)t.add*mul+add)%p;
}
void pushdown(int u){
 eval(tr[u<<1],tr[u].add,tr[u].mul);
 eval(tr[u<<1|1],tr[u].add,tr[u].mul);
 tr[u].add=0,tr[u].mul=1;
}
void build(int u,int l,int r){
 if(l==r)   tr[u]={l,r,w[r],0,1};
 else{
  tr[u]={l,r,0,0,1};
  int mid=l+r>>1;
  build(u<<1,l,mid),build(u<<1|1,mid+1,r);
  pushup(u);
 }
}
void modify(int u,int l,int r,int add,int mul){
 if(tr[u].l>=l && tr[u].r<=r)   eval(tr[u],add,mul);
 else{
  pushdown(u);
  int mid=tr[u].l+tr[u].r>>1;
  if(l<=mid)    modify(u<<1,l,r,add,mul);
  if(r>mid)     modify(u<<1|1,l,r,add,mul);
  pushup(u);  
 }
}
int query(int u,int l,int r){
 if(tr[u].l>=l && tr[u].r<=r)   return tr[u].sum;
 pushdown(u);
 int mid=tr[u].l+tr[u].r>>1;
 int sum=0;
 if(l<=mid)    sum=query(u<<1,l,r);
 if(r>mid)   sum=(sum+query(u<<1|1,l,r))%p;
 return sum;
}
int main(){
 scanf("%d%d",&n,&p);
 for(int i=1;i<=n;i++)   scanf("%d",&w[i]);
 build(1,1,n);
 scanf("%d",&m);
 while(m--){
  int t,l,r,d;
  scanf("%d%d%d",&t,&l,&r);
  if(t==1){
   scanf("%d",&d);
   modify(1,l,r,0,d);
  }
  else if(t==2){
   scanf("%d",&d);
   modify(1,l,r,d,1);
  }
  else  printf("%d\n",query(1,l,r));
 }
 return 0;
}
发布了37 篇原创文章 · 获赞 28 · 访问量 3835

猜你喜欢

转载自blog.csdn.net/qq_45772483/article/details/104335535