zoukankan      html  css  js  c++  java
  • 【模板】线段树 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 }

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

    题目来源:洛谷

  • 相关阅读:
    PHP 大小写转换、首字母大写、每个单词首字母大写转换相关函数
    【论文学习4】BiSample: Bidirectional Sampling for Handling Missing Data with Local Differential Privacy
    【论文学习3】Local Differential Privacy for Deep Learning
    【论文学习2】 Differential Privacy Reinforcement Learning
    深度学习中的优化算法
    Spatial crowdsourcing
    “pip install tensorflow ”出现错误
    python或pip'不是内部或外部命令”
    pip install torch出现错误
    打不开gitHub的解决方法
  • 原文地址:https://www.cnblogs.com/J-william/p/6292437.html
Copyright © 2011-2022 走看看