P3373 【模板】线段树 2 区间求和 区间乘 区间加

题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.将某区间每一个数乘上x

3.求出某区间每一个数的和

输入输出格式

输入格式:

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k

操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果

输出格式:

输出包含若干行整数,即为所有操作3的结果。

输入输出样例

输入样例#1:

5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4

输出样例#1:

17
2

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^)

样例说明:

故输出应为17、2(40 mod 38=2)

根据加减法原理,,

好像只能这么解释,

先放乘法标记

再放加法标记

注意查询的时候ll和rr是不变的

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #define LLI long long
  6 using namespace std;
  7 const LLI MAXN=400001;
  8 LLI read(LLI & n)
  9 {
 10     char p=‘+‘;LLI x=0;
 11     while(p<‘0‘||p>‘9‘)
 12         p=getchar();
 13     while(p>=‘0‘&&p<=‘9‘)
 14     x=x*10+p-48,p=getchar();
 15     n=x;
 16 }
 17 LLI n,m,mod,wl,wr,wv,ans;
 18 struct node
 19 {
 20     LLI l,r,w,fc,fj;
 21 }a[MAXN];
 22 void update(LLI k)
 23 {
 24     a[k].w=(a[k<<1].w+a[k<<1|1].w)%mod;
 25 }
 26 void build_tree(LLI k,LLI ll,LLI rr)
 27 {
 28     a[k].l=ll;a[k].r=rr;
 29     a[k].fc=1;
 30     a[k].fj=0;
 31     if(a[k].l==a[k].r)
 32     {
 33         read(a[k].w);
 34         return ;
 35     }
 36     LLI mid=(ll+rr)/2;
 37     build_tree(k<<1,ll,mid);
 38     build_tree(k<<1|1,mid+1,rr);
 39     update(k);
 40 }
 41 void pushdown(LLI k,LLI ll,LLI rr,LLI mid)
 42 {
 43     a[k<<1].w*=a[k].fc;a[k<<1|1].w*=a[k].fc;
 44     a[k<<1].w+=a[k].fj*(mid-ll+1);a[k<<1|1].w+=a[k].fj*(rr-mid);
 45     a[k<<1].fc*=a[k].fc;a[k<<1|1].fc*=a[k].fc;
 46     a[k<<1].fj*=a[k].fc;a[k<<1|1].fj*=a[k].fc;
 47     a[k<<1].fj+=a[k].fj;a[k<<1|1].fj+=a[k].fj;
 48     a[k].fc=1;a[k].fj=0;
 49     a[k<<1].w%=mod;a[k<<1].fj%=mod;a[k<<1].fc%=mod;
 50     a[k<<1|1].w%=mod;a[k<<1|1].fj%=mod;a[k<<1|1].fc%=mod;
 51 }
 52 void interval_add(LLI k,LLI ll,LLI rr,LLI v)
 53 {
 54     if(a[k].l>rr||a[k].r<ll)
 55         return ;
 56     if(ll<=a[k].l&&rr>=a[k].r)
 57     {
 58         a[k].w=(a[k].w+v*(a[k].r-a[k].l+1))%mod;
 59         a[k].fj=(a[k].fj+v)%mod;
 60         return ;
 61     }
 62     LLI mid=(a[k].l+a[k].r)/2;
 63     pushdown(k,a[k].l,a[k].r,mid);
 64     //if(ll<=mid)
 65     interval_add(k<<1,ll,rr,v);
 66     //if(rr>mid)
 67     interval_add(k<<1|1,ll,rr,v);
 68     update(k);
 69 }
 70 void interval_mul(LLI k,LLI ll,LLI rr,LLI v)
 71 {
 72     if(a[k].l>rr||a[k].r<ll)
 73         return ;
 74     if(ll<=a[k].l&&rr>=a[k].r)
 75     {
 76         a[k].w*=v%mod;
 77         a[k].fc*=v%mod;
 78         a[k].fj*=v%mod;
 79         return ;
 80     }
 81     LLI mid=(a[k].l+a[k].r)/2;
 82     pushdown(k,a[k].l,a[k].r,mid);
 83     //if(ll<=mid)
 84     interval_mul(k<<1,ll,rr,v);
 85     //if(rr>mid)
 86     interval_mul(k<<1|1,ll,rr,v);
 87     update(k);
 88 }
 89 void interval_sum(LLI k,LLI ll,LLI rr)
 90 {
 91     if(a[k].l>rr||a[k].r<ll)
 92         return ;
 93     if(ll<=a[k].l&&rr>=a[k].r)
 94     {
 95         ans=(ans+a[k].w)%mod;
 96         return ;
 97     }
 98     LLI mid=(a[k].l+a[k].r)/2;
 99     pushdown(k,a[k].l,a[k].r,mid);
100     //if(ll<=mid)
101         interval_sum(k<<1,ll,rr);
102     //if(rr>mid)
103         interval_sum(k<<1|1,ll,rr);
104 }
105 int main()
106 {
107     read(n);read(m);read(mod);
108     build_tree(1,1,n);
109     for(LLI i=1;i<=m;i++)
110     {
111         LLI p;
112         read(p);
113         if(p==1)
114         {
115             read(wl);read(wr);read(wv);
116             interval_mul(1,wl,wr,wv);
117         }
118         else if(p==2)
119         {
120             read(wl);read(wr);read(wv);
121             interval_add(1,wl,wr,wv);
122         }
123         else if(p==3)
124         {
125             ans=0;
126             read(wl);read(wr);
127             interval_sum(1,wl,wr);
128             //cout<<ans%mod<<endl;
129             printf("%lld\n",ans%mod);
130         }
131     }
132     return 0;
133 }
时间: 2024-10-20 07:37:03

P3373 【模板】线段树 2 区间求和 区间乘 区间加的相关文章

POJ 3468-A Simple Problem with Integers(线段树:成段更新,区间求和)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 62228   Accepted: 19058 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------

【线段树】HDU 3397 Sequence operation 区间合并

操作 Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters into '1's in [a , b] 2 a b change all '0's into '1's and change all '1's into '0's in [a, b] Output operations: 3 a b output the number of '1's in [a,

poj 1195:Mobile phones(二维线段树,矩阵求和,经典题)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14391   Accepted: 6685 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

Mayor&#39;s posters(线段树之点的成段更新加离散化)

bin神的萌萌哒专题 这道题目也是简单区间更新的线段树题目,不过题目的数据范围很大,直接搞,时间空间的花费都会异常的高,所以就要用到离散化来优化时间空间复杂度. 何为离散化?........................ 简单地说就是对于给出的庞大数据进行一种数据上的缩小. 比如给你一段(1,10000)的区间,由于我们要的不是其区间长度,我们只需要知道这段区间的状态 如何,于是我们可以忽视其长度,把其表示成(1,2)这个区间长度极小的区间,这相当于物理上的质点. 当我们处理的问题上与其区间长

算法模板——线段树1(区间加法+区间求和)

实现功能——1:区间加法:2:区间求和 最基础最经典的线段树模板.由于这里面操作无顺序之分,所以不需要向下pushup,直接累积即可 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end; 8 function min

算法模板——线段树5(区间开根+区间求和)

实现功能——1:区间开根:2:区间求和(此模板以BZOJ3038为例) 作为一个非常规的线段树操作,其tag也比较特殊呵呵哒 1 var 2 i,j,k,l,m,n:longint; 3 a,b:array[0..500000] of int64; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end; 8 function min(x,y:longint):long

算法模板——线段树4(区间加+区间乘+区间覆盖值+区间求和)

实现功能——1:区间加法 2:区间乘法 3:区间覆盖值 4:区间求和 这是个四种常见线段树功能的集合版哦...么么哒(其实只要协调好三种tag的关系并不算太难——前提是想明白了线段树的工作模式) 代码长度几经修改后也大为缩水 还有!!!——通过BZOJ1798反复的尝试,我的出来一个重要结论——尽量减少pushup操作的不必要使用次数,对于程序提速有明显的效果!!! 1 type vet=record 2 a0,a1:longint; 3 end; 4 var 5 i,j,k,l,m,n,a1,

算法模板——线段树3(区间覆盖值+区间求和)

实现功能——1:区间覆盖值:2:区间求和 相比直接的区间加,这个要注重顺序,因为操作有顺序之分.所以这里面的tag应该有个pushup操作(本程序中的ext) 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b,d:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end;

【线段树】线段树系列 0.2单点修改区间求和线段树

1080 线段树练习 题目描述 Description 一行N个方格,开始每个格子里都有一个整数.现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和:修改的规则是指定某一个格子x,加上或者减去一个特定的值A.现在要求你能对每个提问作出正确的回答.1≤N<100000,,提问和修改的总数m<10000条. 输入描述 Input Description 输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数.接下一个正整数m,再接下来有m行,表示