线段树2

Posted scorpiorax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树2相关的知识,希望对你有一定的参考价值。

  1 #include<cstdio>
  2 #include<algorithm>
  3 using namespace std;
  4 typedef long long ll;
  5 const int N=1e6+5;
  6 struct tree
  7 {
  8     int l,r;
  9     ll sum,lz1,lz2;
 10 }t[N];
 11 ll n,m,P;
 12 ll a[N];
 13 void push_up(int p)
 14 {
 15     t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%P;
 16 }
 17 void push_down(int p)
 18 {
 19     if(t[p].l==t[p].r) return;
 20     ll q;
 21     if(t[p].lz1!=1)
 22     {
 23     q=t[p].lz1;
 24     t[p].lz1=1;
 25     t[p<<1].lz1=t[p<<1].lz1*q%P;
 26     t[p<<1].lz2=t[p<<1].lz2*q%P;
 27     t[p<<1|1].lz1=t[p<<1|1].lz1*q%P;
 28     t[p<<1|1].lz2=t[p<<1|1].lz2*q%P;
 29     t[p<<1].sum=t[p<<1].sum*q%P;
 30     t[p<<1|1].sum=t[p<<1|1].sum*q%P;
 31     }
 32     if(t[p].lz2)
 33     {
 34     q=t[p].lz2;
 35     t[p].lz2=0;
 36     t[p<<1].lz2=(t[p<<1].lz2+q)%P;
 37     t[p<<1|1].lz2=(t[p<<1|1].lz2+q)%P;
 38     t[p<<1].sum=(t[p<<1].sum+(t[p<<1].r-t[p<<1].l+1)*q)%P;
 39     t[p<<1|1].sum=(t[p<<1|1].sum+(t[p<<1|1].r-t[p<<1|1].l+1)*q)%P;
 40     }
 41 }
 42 
 43 void build(int p,int l,int r)
 44 {
 45     t[p].l=l;t[p].r=r;t[p].sum=t[p].lz2=0;t[p].lz1=1;
 46     if(l==r) return (void)(t[p].sum=a[l]);
 47     int mid=l+r>>1;
 48     build(p<<1,l,mid);
 49     build(p<<1|1,mid+1,r);
 50     push_up(p);
 51 }
 52 void modify1(int p,int l,int r,ll w)
 53 {
 54     if(l==t[p].l && r==t[p].r)
 55     {
 56     t[p].lz1=t[p].lz1*w%P;
 57     t[p].lz2=t[p].lz2*w%P;
 58     t[p].sum=t[p].sum*w%P;
 59     return;
 60     }
 61     push_down(p);
 62     int mid=t[p].l+t[p].r>>1;
 63     if(mid>=r) modify1(p<<1,l,r,w);
 64     else if(l>mid) modify1(p<<1|1,l,r,w);
 65     else modify1(p<<1,l,mid,w),modify1(p<<1|1,mid+1,r,w);
 66     push_up(p);
 67 }
 68 void modify2(int p,int l,int r,ll w)
 69 {
 70     if(l==t[p].l && r==t[p].r)
 71     {
 72     t[p].lz2=(t[p].lz2+w)%P;
 73     t[p].sum=(t[p].sum+(t[p].r-t[p].l+1)*w)%P;
 74     return;
 75     }
 76     push_down(p);
 77     int mid=t[p].l+t[p].r>>1;
 78     if(mid>=r) modify2(p<<1,l,r,w);
 79     else if(l>mid) modify2(p<<1|1,l,r,w);
 80     else modify2(p<<1,l,mid,w),modify2(p<<1|1,mid+1,r,w);
 81     push_up(p);
 82 }
 83 ll query(int p,int l,int r)
 84 {
 85     //  printf("%d %d %d %d %lld\n",l,r,t[p].l,t[p].r,t[p].sum);
 86     if(l==t[p].l && r==t[p].r) return t[p].sum;
 87     push_down(p);
 88     int mid=t[p].l+t[p].r>>1;
 89 
 90     if(mid>=r) return query(p<<1,l,r);
 91     if(l>mid) return query(p<<1|1,l,r);
 92     return (query(p<<1,l,mid)+query(p<<1|1,mid+1,r))%P;
 93 }
 94 int main()
 95 {
 96     scanf("%lld%lld%lld",&n,&m,&P);
 97     for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
 98     build(1,1,n);
 99     ll k;
100     for(int i=1,op,x,y;i<=m;i++)
101     {
102 //    for(int i=1;i<=n;i++) printf("%d:%lld\n",i,query(1,i,i));
103     scanf("%d",&op);
104     if(op==1)scanf("%d%d%lld",&x,&y,&k),modify1(1,x,y,k);
105     if(op==2)scanf("%d%d%lld",&x,&y,&k),modify2(1,x,y,k);
106     if(op==3)scanf("%d%d",&x,&y),printf("%lld\n",query(1,x,y));
107       
108     }
109     return 0;
110 }

 

题目描述

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

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)

 

以上是关于线段树2的主要内容,如果未能解决你的问题,请参考以下文章

线段树

高级数据结构线段树

数据结构线段树笔记2

线段树2

luogu3373线段树2..支持区间加值和乘值的线段树

数据结构 ---[实现 线段树(SegmentTree) ]