• [线段树模板题] 线段树2


    洛谷原题

    第二次做 线段树2 了,之前研究了两节晚自习自以为完全理解了,但是今天写还是有一点小差错,值得反思。

    稍微总结下线段树2的要点。

    <1> 乘法标记影响加法标记,更新 乘法标记 时应将对应的 加法标记 乘上 乘法标记乘的值(key)

    <2> 标记下传中 乘法标记 应优先于 加法标记,由于我们在更新 乘法标记 时更新了 加法标记,所以如果乘法不优先的话,先乘再加的操作会出现误差

    <3> 加或乘的操作中每一层算完儿子节点后都应更新当前节点信息,查询则不需要,更新操作只在 子区间 和 其子区间(down) 中进行,所以父区间都应由儿子更新

    <4> memset有毒,害我找了40+分钟错误,我一开始用memset将乘法标记设为1,但样例怎么样都过不了,还是看了之前自己的题解,改成 建树过程中将标记设为1 才AC的

    下面是我的代码(以前代码是真的丑)

    #include <bits/stdc++.h>
    using namespace std; 
    long long a[100005],he[800005],lazy[800005],hard[800005];
    int ll,rr,n,m;
    long long ans,P;
    void biu(int t,int l,int r)
    {
        hard[t]=1;//memset有毒,别用 
        if(l==r)
        {
            he[t]=a[l]%P;
            return;
        }
        int mid=l+r>>1;
        biu(2*t,l,mid);
        biu(2*t+1,mid+1,r);
        he[t]=(he[2*t]+he[2*t+1])%P;
        return;
    }
    void down(int t,int l,int r)//标记下传 
    {
        if(lazy[t]==0&&hard[t]==1) return;
        //乘法优先:乘标记影响加标记
        lazy[2*t]=(lazy[2*t]*hard[t])%P;
        lazy[2*t+1]=(lazy[2*t+1]*hard[t])%P;
         
        hard[2*t]=(hard[2*t]*hard[t])%P;
        hard[2*t+1]=(hard[2*t+1]*hard[t])%P;
        
        lazy[2*t]=(lazy[2*t]+lazy[t])%P;
        lazy[2*t+1]=(lazy[2*t+1]+lazy[t])%P;
        
        int mid=l+r>>1;
        he[2*t]=(((he[2*t]*hard[t])%P)+((lazy[t]*(mid-l+1))%P))%P;
        he[2*t+1]=(((he[2*t+1]*hard[t])%P)+((lazy[t]*(r-mid))%P))%P;
        hard[t]=1;
        lazy[t]=0;
    }
    void ask(int t,int l,int r)
    {
        if(ll<=l&&r<=rr)
        {
            ans=(ans+he[t])%P;
            return;
        }
        down(t,l,r);
        int mid=l+r>>1;
        if(ll<=mid) ask(2*t,l,mid);
        if(rr> mid) ask(2*t+1,mid+1,r);
        //he[t]=(he[2*t]+he[2*t+1])%P; 没更新 ,不用加 
        return;
    }
    void jia(int t,int l,int r,long long key)
    {
        if(ll<=l&&r<=rr)
        {
            he[t]=(he[t]+((r-l+1)*key%P))%P;
            lazy[t]=(lazy[t]+key)%P;
            return;
        }
        int mid=l+r>>1;
        down(t,l,r);
        if(ll<=mid) jia(2*t,l,mid,key);
        if(rr> mid) jia(2*t+1,mid+1,r,key);
        he[t]=(he[2*t]+he[2*t+1])%P;
        return;
    }
    void cheng(int t,int l,int r,long long key)
    {
        if(ll<=l&&r<=rr)
        {
            he[t]=(he[t]*key)%P;
            hard[t]=(hard[t]*key)%P;
            lazy[t]=(lazy[t]*key)%P;
            //printf("Edge %d sum=%lld
    ",t,he[t]);
            return;
        }
        int mid=l+r>>1;
        down(t,l,r);
        if(ll<=mid) cheng(2*t,l,mid,key);
        if(rr> mid) cheng(2*t+1,mid+1,r,key);
        he[t]=(he[2*t]+he[2*t+1])%P;
        return;
    }
    int main()  
    {  
        scanf("%d%d%lld",&n,&m,&P);
        int x;long long k;
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        //memset(hard,1,sizeof(hard));
        biu(1,1,n);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&x);
            if(x==1){scanf("%d%d%lld",&ll,&rr,&k);cheng(1,1,n,k);}
            if(x==2){scanf("%d%d%lld",&ll,&rr,&k);  jia(1,1,n,k);}
            if(x==3){scanf("%d%d",&ll,&rr);ask(1,1,n);printf("%lld
    ",ans);ans=0;}
        }
        return 0;  
    }  
  • 相关阅读:
    吴裕雄--天生自然 JAVASCRIPT开发学习:函数定义
    吴裕雄--天生自然 JAVASCRIPT开发学习: JSON
    吴裕雄--天生自然 JAVASCRIPT开发学习: this 关键字
    吴裕雄--天生自然 JAVASCRIPT开发学习: 验证 API
    吴裕雄--天生自然 JAVASCRIPT开发学习: 表单验证
    吴裕雄--天生自然 JAVASCRIPT开发学习: 表单
    吴裕雄--天生自然 JAVASCRIPT开发学习: 变量提升
    吴裕雄--天生自然 JAVASCRIPT开发学习: 错误
    【codeforces 742A】Arpa’s hard exam and Mehrdad’s naive cheat
    【codeforces 742B】Arpa’s obvious problem and Mehrdad’s terrible solution
  • 原文地址:https://www.cnblogs.com/Miniweasel/p/9893588.html
Copyright © 2020-2023  润新知