• 线段树2


      本以为自己对线段树已经掌握得很好,做完这道题,感觉自己又收货了很多。

      首先我们要定义运算的优先顺序,因为对于两个lazy标记,我们不知道是应该先乘还是应该先加,所以我们就规定:先乘再加,就这么定了!

      可是别高兴太早呀!我们虽然规定了顺序,但是这不一定是真正的顺序,比如 ( a + b ) * c 和 a * c + b 是不一样的,所以呐,我们略加观察——嘿!原来在原有基础上乘一个数,和先乘这个数,与加上加法lazy乘这个 数的和是一样的!那么,我们就可以这样:如果加一个数,就直接加在加法lazy上;如果是乘一个数,那么我们除了在乘法lazy里乘上这个数以外,也在加法lazy里乘这个数,这样先乘后加就一定不会有错啦!当然前提是乘法标记一开始都是1!

      还有一件事,就是lazy标记的下传。比如儿子节点是 ac + b ,父亲节点乘法标记和加法标记是 x , y 。那这个值应该是  ( ac + b ) * x + y,展开后就是 acx + bx + y,那我们发现,这就是在儿子节点的初始权值和的基础上,乘法标记是 c * x ,加法标记是 bx + y。所以我们可以乘法直接乘,加法先乘上父亲节点的乘法标记,再加上父亲节点的加法标记,就是下传后的标记了。

      那话不多说啦(已经说很多了),代码如下:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 2000010
    #define int long long 
    struct node
    {
        int sum,add,mul;
    } e[maxn];
    int l[maxn],r[maxn];
    int n,m,p;
    int add(int a,int b)
    {
        return (a+b)%p;
    }
    int mul(int a,int b)
    {
        return (a*b)%p;
    }
    void push_down(int now)
    {
        int ls=now*2;
        int rs=now*2+1;
        int mid=(l[now]+r[now])/2;
        e[ls].sum=mul(e[ls].sum,e[now].mul);
        e[ls].sum=add(e[ls].sum,e[now].add*(r[ls]-l[ls]+1));
        e[rs].sum=mul(e[rs].sum,e[now].mul);
        e[rs].sum=add(e[rs].sum,e[now].add*(r[rs]-l[rs]+1));
        
        e[ls].mul=mul(e[ls].mul,e[now].mul);
        e[rs].mul=mul(e[rs].mul,e[now].mul);
        
        e[ls].add=mul(e[ls].add,e[now].mul);
        e[ls].add=add(e[ls].add,e[now].add);
        e[rs].add=mul(e[rs].add,e[now].mul);
        e[rs].add=add(e[rs].add,e[now].add);
        
        e[now].mul=1;
        e[now].add=0;
    }
    void build(int L,int R,int now)
    {
        e[now].mul=1;
        e[now].add=0;
        l[now]=L;
        r[now]=R;
        if(L==R) 
        {
            scanf("%lld",&e[now].sum);
            e[now].sum%=p;
            return;    
        }
        int mid=(L+R)/2;
        build(L,mid,now*2);
        build(mid+1,R,now*2+1);
        e[now].sum=add(e[now*2].sum,e[now*2+1].sum);
        return ;
    }
    void update_add(int now,int L,int R,int k)
    {
        if(L<=l[now]&&r[now]<=R)
        {
            e[now].add=add(e[now].add,k);
            e[now].sum=add(e[now].sum,k*(r[now]-l[now]+1));
            return ;
        }
        push_down(now);
        int mid=(l[now]+r[now])/2;
        if(mid>=L) update_add(now*2,L,R,k);
        if(mid<R) update_add(now*2+1,L,R,k);
        e[now].sum=add(e[now*2].sum,e[now*2+1].sum); 
    }
    void update_mul(int now,int L,int R,int k)
    {
        if(L<=l[now]&&r[now]<=R)
        {
            e[now].mul=mul(e[now].mul,k);
            e[now].add=mul(e[now].add,k);
            e[now].sum=mul(e[now].sum,k);
            return ;
        }
        push_down(now);
        int mid=(l[now]+r[now])/2;
        if(mid>=L) update_mul(now*2,L,R,k);
        if(mid<R) update_mul(now*2+1,L,R,k);
        e[now].sum=add(e[now*2].sum,e[now*2+1].sum);
    } 
    int query(int now,int L,int R)
    {
        if(L<=l[now]&&r[now]<=R)
            return e[now].sum;
        push_down(now);
        int mid=(l[now]+r[now])/2;
        int ans=0;
        if(L<=mid) ans=query(now*2,L,R)%p;
        if(mid<R) ans=add(ans,query(now*2+1,L,R));
        return ans; 
    }
    main()
    {
        scanf("%lld%lld%lld",&n,&m,&p);
        build(1,n,1);    
        for(int i=1;i<=m;i++)
        {
            int op,x,y,k;
            scanf("%lld%lld%lld",&op,&x,&y);
            if(op==1)
            {
                scanf("%lld",&k);
                update_mul(1,x,y,k);
            }
            else if(op==2)
            {
                scanf("%lld",&k);
                update_add(1,x,y,k); 
            }
            else
                printf("%lld
    ",query(1,x,y));
        }
        return 0;
    }

      啊啊啊,还有一道序列操作没 d 出来……

      所以——

      睡觉去了!

      >\<

  • 相关阅读:
    base64图片上传及回显
    C++类型转换
    threejs求两个向量的夹角
    实验数据记录
    工控机配置日志
    threejs两个向量旋转 一个向量绕零一个向量旋转一个角度后的向量计算
    SpringBootApplication cannot be resolved to a type
    python struct pack unpack
    日志
    python计算空间中两个向量的夹角
  • 原文地址:https://www.cnblogs.com/popo-black-cat/p/10353394.html
Copyright © 2020-2023  润新知