• 【模板】线段树 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)

    思路:

    问题主要是没法分断是先乘还是先加,我同学说可以能个栈存一下,线段树里的栈。。。恕我无能。

    一般的解决方法是把乘法变成加法。

    ①:s*lazy+flag.

    ②:(s+flag)*lazy=s*lazy+flag*lazy.

    注意:

    数据规模,不仅要开long long,还要时常取mod。

    (根据评论中的话,好像不开long long也行,但即使数据是int范围内的,因为有乘法操作,可能会动不动就到了long long范围内。noip时,Linux格式化输入输出lld。)

    代码实现:

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 #define LL long long
     5 LL n,m,mod,a,b,c,d;
     6 struct nate{LL l,r,s,flag,lazy;}t[800000];//flag
     7 void heritage(LL k){//标记传递。
     8     if(t[k].lazy==1&&t[k].flag==0) return;
     9     if(t[k].l==t[k].r){t[k].flag=0;t[k].lazy=1;return;}
    10     LL lson=k*2,rson=k*2+1;
    11     t[lson].s=((t[lson].s*t[k].lazy)%mod+(t[k].flag*(t[lson].r-t[lson].l+1))%mod)%mod;
    12     t[lson].flag=((t[lson].flag*t[k].lazy)%mod+t[k].flag)%mod;
    13     t[lson].lazy=(t[lson].lazy*t[k].lazy)%mod;//传递到左儿子。
    14     t[rson].s=((t[rson].s*t[k].lazy)%mod+(t[k].flag*(t[rson].r-t[rson].l+1))%mod)%mod;
    15     t[rson].flag=((t[rson].flag*t[k].lazy)%mod+t[k].flag)%mod;
    16     t[rson].lazy=(t[rson].lazy*t[k].lazy)%mod;//传递到右儿子。
    17     t[k].flag=0;t[k].lazy=1;
    18 }
    19 void make_tree(LL k,LL l,LL r){//建树。一般建法。
    20     LL lson=k*2,rson=k*2+1;
    21     t[k].l=l;t[k].r=r;t[k].lazy=1;//lazy是倍数标记,初值要赋成1!
    22     if(l==r){scanf("%lld",&t[k].s);t[k].s%=mod;return;}
    23     LL mid=(l+r)/2;
    24     make_tree(lson,l,mid);
    25     make_tree(rson,mid+1,r);
    26     t[k].s=(t[lson].s+t[rson].s)%mod;
    27 }
    28 void interval_add(LL k,LL l,LL r,LL v){//加法更值。
    29     LL lson=k*2,rson=k*2+1;
    30     heritage(k);//注意位置。
    31     if(t[k].l==l&&t[k].r==r){
    32         t[k].flag=v;//flag等于新值。
    33         t[k].s=(t[k].s+((t[k].r-t[k].l+1)*v)%mod)%mod;//新值加上,准备传递。
    34         return;
    35     }
    36     LL mid=(t[k].l+t[k].r)/2;
    37     if(l<=mid) interval_add(lson,l,min(r,mid),v);
    38     if(r>mid) interval_add(rson,max(l,mid+1),r,v);
    39     t[k].s=(t[lson].s+t[rson].s)%mod;
    40 }
    41 void interval_ride(LL k,LL l,LL r,LL v){//乘法更值。
    42     LL lson=k*2,rson=k*2+1;
    43     heritage(k);//注意位置。
    44     if(t[k].l==l&&t[k].r==r){
    45         t[k].lazy=v;//换成新值。
    46         t[k].s=(t[k].s*v)%mod;//新值乘上,准备传递。
    47         return;
    48     }
    49     LL mid=(t[k].l+t[k].r)/2;
    50     if(l<=mid) interval_ride(lson,l,min(r,mid),v);
    51     if(r>mid) interval_ride(rson,max(l,mid+1),r,v);
    52     t[k].s=(t[lson].s+t[rson].s)%mod;
    53 }
    54 LL interval_query(LL k,LL l,LL r){//区间查询。
    55     int lson=k*2,rson=k*2+1;
    56     heritage(k);
    57     if(t[k].l==l&&t[k].r==r) return t[k].s;
    58     LL mid=(t[k].l+t[k].r)/2,ans=0;
    59     if(l<=mid) ans+=interval_query(lson,l,min(r,mid));
    60     if(r>mid) ans+=interval_query(rson,max(l,mid+1),r);
    61     return ans%mod;
    62 }
    63 int main(){
    64     scanf("%lld%lld%lld",&n,&m,&mod);
    65     make_tree(1,1,n);
    66     for(int i=1;i<=m;i++){
    67         scanf("%lld",&a);
    68         if(a==1){
    69             scanf("%lld%lld%lld",&b,&c,&d);
    70             interval_ride(1,b,c,d%mod);
    71         }
    72         if(a==2){
    73             scanf("%lld%lld%lld",&b,&c,&d);
    74             interval_add(1,b,c,d%mod);
    75         }
    76         if(a==3){
    77             scanf("%lld%lld",&b,&c);
    78             printf("%lld
    ",interval_query(1,b,c));
    79         }
    80     }
    81     return 0;
    82 }

    有没有感觉很恶心,慢慢来吧。

    题目来源:洛谷

  • 相关阅读:
    python中的json
    vmware workstation中的NAT配置
    python内置的一些模块
    datetime
    线程池的工作过程示例
    java io read中申请读的长度与实际长度不同|RocketMQ源码
    RocketMQ集群搭建及安装rocketmq-console
    使用MAT分析JVM内存溢出
    jdbcTemplate小用总结
    Spring线程安全为何非安全,场景重现,解决安全小结
  • 原文地址:https://www.cnblogs.com/J-william/p/6292437.html
Copyright © 2020-2023  润新知