洛谷3374 线段树2

来源:互联网 发布:io1.1鼠标淘宝哪家最好 编辑:程序博客网 时间:2024/06/07 12:28

题目描述

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

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)

Q

注意:
1.取模要彻底!
2.先*后+;
3.lazy标记是+=不是只有=!;
4.push要加if判断;

在query中,用push后不用up是因为:父节点的值已经确定(push前),子节点的值没有修改;
push的前提就是父节点值已经确定,因此push完后lazy标记改为0;

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;const ll MAXN=500001;ll n,m,p,num[MAXN];struct hh{    ll delta,l,r,sum,add;}tree[MAXN];void up(ll now){    tree[now].sum=((tree[now<<1].sum%p)+(tree[now<<1|1].sum%p))%p;    return;}void build_tree(ll now,ll l,ll r){    ll mid=(l+r)>>1;    tree[now].l=l;    tree[now].r=r;    tree[now].add=1;    tree[now].delta=0;    if(l==r) {tree[now].sum=num[l]%p;return;}    build_tree(now<<1,l,mid);    build_tree(now<<1|1,mid+1,r);    up(now);    return;}void push(ll now){    if(tree[now].add!=1)    {        tree[now<<1].add=(tree[now].add*tree[now<<1].add)%p;        tree[now<<1].sum=(tree[now].add*tree[now<<1].sum)%p;        tree[now<<1|1].add=(tree[now<<1|1].add*tree[now].add)%p;        tree[now<<1|1].sum=(tree[now<<1|1].sum*tree[now].add)%p;        tree[now<<1].delta=(tree[now<<1].delta*tree[now].add)%p;        tree[now<<1|1].delta=(tree[now<<1|1].delta*tree[now].add)%p;        tree[now].add=1;    }    if(tree[now].delta)    {        tree[now<<1].sum=(tree[now<<1].sum%p+(tree[now<<1].r-tree[now<<1].l+1)*tree[now].delta)%p;        tree[now<<1].delta=(tree[now<<1].delta+tree[now].delta)%p;        tree[now<<1|1].sum=(tree[now<<1|1].sum%p+(tree[now<<1|1].r-tree[now<<1|1].l+1)*tree[now].delta)%p;        tree[now<<1|1].delta=(tree[now].delta+tree[now<<1|1].delta)%p;        tree[now].delta=0;    }    return;}void change_1(ll now,ll l,ll r,ll v){    if(v==1) return;    if(tree[now].l>=l && tree[now].r<=r)    {        tree[now].sum=(tree[now].sum*v)%p;        tree[now].add=(tree[now].add*v)%p;        tree[now].delta=(tree[now].delta*v)%p;        return;    }    push(now);    ll mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid) change_1(now<<1,l,r,v);    if(r>=mid+1) change_1(now<<1|1,l,r,v);    up(now);    return;}void change_2(ll now,ll l,ll r,ll v){    if(tree[now].l>=l && tree[now].r<=r)     {        tree[now].sum=((tree[now].r-tree[now].l+1)*v+tree[now].sum)%p;        tree[now].delta=(tree[now].delta+v)%p;        return;    }    push(now);    ll mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid) change_2(now<<1,l,r,v);    if(r>=mid+1) change_2(now<<1|1,l,r,v);    up(now);    return;}ll query(ll now,ll l,ll r){    if(tree[now].l>=l && tree[now].r<=r) return tree[now].sum%p;    push(now);    ll ans=0,mid=(tree[now].l+tree[now].r)>>1;    if(l<=mid) ans=(ans+query(now<<1,l,r))%p;    if(r>=mid+1) ans=(ans+query(now<<1|1,l,r))%p;    return ans%p;}void solve(){    cin>>n>>m>>p;    for(ll i=1;i<=n;i++) scanf("%lld",&num[i]);    build_tree(1,1,n);    while(m--)    {        ll opt,x,y,k;        scanf("%lld%lld%lld",&opt,&x,&y);        switch(opt)        {            case 1: scanf("%lld",&k),change_1(1,x,y,k%p);break;            case 2: scanf("%lld",&k),change_2(1,x,y,k%p);break;            case 3: printf("%lld\n",query(1,x,y)%p);break;        }    }    return;}int main(){    solve();    return 0;}
原创粉丝点击