Transformation HDU - 4578

写之前看到了大佬的文章,思路请移步大佬文章
链接Transformation HDU - 4578 多重懒标记 || 简洁暴力做法
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=4578
多重懒标记暴力做法

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;
const int maxn = 100010;
const ll mod = 10007;

ll sum[maxn<<2][3],mul[maxn<<2],add[maxn<<2],cha[maxn<<2];

void Build(int l,int r,int rt)
{
    sum[rt][0] = sum[rt][1] = sum[rt][2] = 0;
    add[rt] = 0,mul[rt] = 1,cha[rt] = 0;
    if(l == r){
        return ;
    }
    int m = (l + r)>>1;
    Build(l,m,rt<<1);
    Build(m + 1,r,rt<<1|1);
}

void PushUp(int rt)
{
    for(int i = 0; i < 3; i++){
        sum[rt][i] = (sum[rt<<1][i] + sum[rt<<1|1][i]) % mod;
    }
}

//更新加法
void Up1(int rt,int l,int r,ll val)
{
    int len = r - l + 1;
    //加法时次方和更新顺序必须是3->2->1;
    sum[rt][2] = (sum[rt][2]+val*val%mod*val%mod*len%mod+3*val*sum[rt][1]%mod+3*val*val%mod*sum[rt][0]%mod) % mod;
    sum[rt][1]=(sum[rt][1]+val*val%mod*len%mod+2*val*sum[rt][0]%mod) % mod;
    sum[rt][0]=(sum[rt][0]+val*len) % mod;
}

//更新乘法
void Up2(int rt,ll val)
{
    sum[rt][2] = sum[rt][2] * val % mod * val % mod * val % mod;
    sum[rt][1] = sum[rt][1] * val % mod * val % mod;
    sum[rt][0] = sum[rt][0] * val % mod;
}

//更新改值操作
void Up3(int rt,int l,int r,ll val)
{
    int len = r - l + 1;
    sum[rt][0] = val * len % mod;
    sum[rt][1] = val * val % mod * len % mod;
    sum[rt][2] = val * val % mod * val % mod * len % mod;
}

//优先级:更改值->乘法->加法
void PushDown(int l,int r,int rt)
{
    int lr = rt<<1,rr = rt<<1|1;
    int m = (l + r)>>1;
    if(cha[rt]){
        cha[lr] = cha[rr] = cha[rt];
        mul[lr] = mul[rr] = 1;
        add[lr] = add[rr] = 0;
        ll val = cha[rt];
        Up3(lr,l,m,val);
        Up3(rr,m + 1,r,val);
        cha[rt] = 0;
    }
    /*这里优先级乘法大于加法,因为如果先加后乘,如果目标指令是先乘再加
    结果却变成了先加再乘,导致错误*/
    if(mul[rt] != 1){
        mul[lr] = mul[lr] * mul[rt] % mod;
        mul[rr] = mul[rr] * mul[rt] % mod;
        add[lr] = add[lr] * mul[rt] % mod;
        add[rr] = add[rr] * mul[rt] % mod;
        Up2(lr,mul[rt]);
        Up2(rr,mul[rt]);
        mul[rt] = 1;
     }
     if(add[rt]){
        add[lr] = (add[lr] + add[rt]) % mod;
        add[rr] = (add[rr] + add[rt]) % mod;
        Up1(lr,l,m,add[rt]);
        Up1(rr,m + 1,r,add[rt]);
        add[rt]  = 0;
     }
}

void Update(int L,int R,int oper,ll val,int l,int r,int rt)
{
    if(L <= l&&r <= R){
        if(oper == 3){
            Up3(rt,l,r,val);
            mul[rt] = 1,add[rt] = 0,cha[rt] = val;
        }
        else if(oper == 2){
            Up2(rt,val);
            mul[rt] = mul[rt] * val % mod;
            /*保证按照PushDown中的下推顺序
            更新左右节点还是会按照规定的顺序进行运算*/
            add[rt] = add[rt] * val % mod;
        }
        else{
            Up1(rt,l,r,val);
            add[rt] = (add[rt] + val) % mod;
        }
        return ;
    }
    PushDown(l,r,rt);
    int m = (l + r)>>1;
    if(L <= m){
        Update(L,R,oper,val,l,m,rt<<1);
    }
    if(R > m){
        Update(L,R,oper,val,m + 1,r,rt<<1|1);
    }
    PushUp(rt);
}

ll Query(int L,int R,int l,int r,int rt,int oper)
{
    if(L <= l&&r<=R){
        return sum[rt][oper] % mod;
    }
    PushDown(l,r,rt);
    int m = (l + r)>>1;
    ll ans = 0;
    if(L <= m){
        ans += Query(L,R,l,m,rt<<1,oper) % mod;
    }
    if(R > m){
        ans += Query(L,R,m + 1,r,rt<<1|1,oper) % mod;
    }
    return ans % mod;
}

int main()
{
    int m,n;
    while(scanf("%d%d",&n,&m),n){
        Build(1,n,1);
        while(m--){
            int oper,l,r;
            ll val;
            scanf("%d%d%d%lld",&oper,&l,&r,&val);
            if(oper <= 3){
                Update(l,r,oper,val,1,n,1);
            }
            else{
                ll ans = Query(l,r,1,n,1,val - 1) % mod;
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}
/*
5 5
3 3 5 7
1 2 4 4
4 1 5 2
2 2 5 8
4 3 5 3
0 0
*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值