HDU 4578 Transformation(最恶心的线段树)

题目分析

这道题首先可以发现第三种操作和第二种操作都是很简单的,这里我就不多说了,但是对于加操作就有点需要特殊处理了 (a+b)3=a3+3a2b+3ab2+b3 很明显这样就可以推出来了,因为 a3,a2,a 都是已知的,因此可以处理了,注意先处理 (a+b)3 然后处理 (a+b)2 再处理 (a+b) 因为前面的需要用到后面的值,如果后面的更新了那么得到的结果就不对了。
除此之外还需要处理的就是3种操作的顺序,很明显对于第一种操作而言前2种操作可以直接忽略,但是对于第二种和第三种操作就不行了。我们用 add[o],mul[o],val[o] 分别代表三种操作的标记。
那么很明显如果val[o]有值应该首先处理,因为说明这个操作在第二种和第一种操作前面,不然的话mul[o]和add[o]都被设置为初始值了,然后处理第二种操作,如果在此之前已经有第一种操作,我们直接让add[o]乘以对应的值就可以了,不懂的可以想一想为什么。总之更新一定要注意顺序。
这道题程序挺复杂,因为手残错了n次,忘仔细思考再做。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5+10;
const int mod = 10007;
#define mid (L+R)/2
#define lson o<<1, L, mid
#define rson o<<1|1, mid+1, R

int sum1[maxn<<2], sum2[maxn<<2], sum3[maxn<<2];
int val[maxn<<2], add[maxn<<2], mul[maxn<<2];

void pushup(int o, int len){
    if(len == 1) return ;
    sum1[o] = (sum1[o<<1] + sum1[o<<1|1])%mod;
    sum2[o] = (sum2[o<<1] + sum2[o<<1|1])%mod;
    sum3[o] = (sum3[o<<1] + sum3[o<<1|1])%mod;
}

void pushdown(int o, int len){
    if(len == 1) return ;
    if(val[o] != -1){
        val[o<<1] = val[o<<1|1] = val[o];
        add[o<<1] = add[o<<1|1] = 0;
        mul[o<<1] = mul[o<<1|1] = 1;
        sum1[o<<1] = (len-(len>>1))%mod*val[o]%mod;
        sum2[o<<1] = ((len-(len>>1))%mod)*(val[o]*val[o]%mod)%mod;
        sum3[o<<1] = ((len-(len>>1))%mod)*((val[o]*val[o]%mod)*val[o]%mod)%mod;
        sum1[o<<1|1] = ((len>>1)%mod)*val[o]%mod;
        sum2[o<<1|1] = ((len>>1)%mod)*(val[o]*val[o]%mod)%mod;
        sum3[o<<1|1] = ((len>>1)%mod)*((val[o]*val[o]%mod)*val[o]%mod)%mod;
        val[o] = -1;
    }
    if(mul[o] != 1){
        mul[o<<1] = (mul[o]*mul[o<<1])%mod, mul[o<<1|1] = (mul[o]*mul[o<<1|1])%mod;
        add[o<<1] = add[o<<1]*mul[o]%mod, add[o<<1|1] = add[o<<1|1]*mul[o]%mod;
        sum1[o<<1] = sum1[o<<1]*mul[o]%mod;
        sum2[o<<1] = (sum2[o<<1]*mul[o]%mod)*mul[o]%mod;
        sum3[o<<1] = ((sum3[o<<1]*mul[o]%mod)*mul[o]%mod)*mul[o]%mod;
        sum1[o<<1|1] = sum1[o<<1|1]*mul[o]%mod;
        sum2[o<<1|1] = (sum2[o<<1|1]*mul[o]%mod)*mul[o]%mod;
        sum3[o<<1|1] = ((sum3[o<<1|1]*mul[o]%mod)*mul[o]%mod)*mul[o]%mod;
        mul[o] = 1;
    }
    if(add[o]){
        add[o<<1] = (add[o]+add[o<<1])%mod;
        add[o<<1|1] = (add[o]+add[o<<1|1])%mod;
        sum3[o<<1] = (sum3[o<<1] + (3*sum2[o<<1]*add[o])%mod + 3*(sum1[o<<1]*add[o]%mod)*add[o]%mod + ((add[o]*add[o]%mod)*add[o]%mod)*(len-(len>>1))%mod)%mod;
        sum3[o<<1|1] = (sum3[o<<1|1] + (3*sum2[o<<1|1]*add[o])%mod + 3*(sum1[o<<1|1]*add[o]%mod)*add[o]%mod + ((add[o]*add[o]%mod)*add[o]%mod)*(len>>1)%mod)%mod;
        sum2[o<<1] = (sum2[o<<1] + (2*sum1[o<<1]*add[o])%mod + (add[o]*add[o]%mod)*(len-(len>>1))%mod)%mod;
        sum2[o<<1|1] = (sum2[o<<1|1] + (2*sum1[o<<1|1]*add[o])%mod + (add[o]*add[o]%mod)*(len>>1)%mod)%mod;
        sum1[o<<1] = (sum1[o<<1] + add[o]*(len-(len>>1))%mod)%mod;
        sum1[o<<1|1] = (sum1[o<<1|1] + add[o]*(len>>1)%mod)%mod;
        add[o] = 0;
    }
}

void build(int o,int L,int R){   //初始化
    add[o] = 0, mul[o] = 1, val[o] = -1;
    sum1[o] = sum2[o] = sum3[o] = 0;
    if(L == R) return ;
    build(lson);
    build(rson);
}

void update(int o, int L, int R, int op, int l, int r, int c){
    if(l <= L && R <= r){
        c = c%mod;
        if(op == 1){
            add[o] =(add[o] + c)%mod;
            sum3[o] = (sum3[o] + 3*sum2[o]%mod*c%mod + 3*sum1[o]%mod*c%mod*c%mod + c*c%mod*c%mod*(R-L+1)%mod)%mod;
            sum2[o] = (sum2[o] + 2*sum1[o]%mod*c%mod + c*c%mod*(R-L+1)%mod)%mod;
            sum1[o] = (sum1[o] + c*(R-L+1)%mod)%mod;
        }
        else if(op == 2){
            add[o] = add[o]*c%mod;
            mul[o] = mul[o]*c%mod;
            sum1[o] = sum1[o]*c%mod;
            sum2[o] = (sum2[o]*c%mod)*c%mod;
            sum3[o] = ((sum3[o]*c%mod)*c%mod)*c%mod;
        }
        else if(op == 3){
            val[o] = c, add[o] = 0, mul[o] = 1;
            sum1[o] = ((R-L+1)%mod)*c%mod;
            sum2[o] = ((R-L+1)%mod)*(c*c%mod)%mod;
            sum3[o] = ((R-L+1)%mod)*((c*c%mod)*c%mod)%mod;
        }
        return ;
    }
    pushdown(o, R-L+1);
    if(l <= mid) update(lson, op, l, r, c);
    if(r > mid) update(rson, op, l, r, c);
    pushup(o, R-L+1);
}

int query(int o, int L, int R, int l, int r, int c){
    if(l <= L && R <= r){
        if(c == 1) return sum1[o];
        else if(c == 2) return sum2[o];
        else return sum3[o];
    }
    pushdown(o, R-L+1);
    int ret = 0;
    if(l <= mid) ret = (ret + query(lson, l, r, c))%mod;
    if(r > mid) ret = (ret + query(rson, l, r, c))%mod;
    return ret;
}

int main(){
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF){
        if(!n && !m) break;
        build(1, 1, n);
        int op, x, y, c;
        while(m--){
            scanf("%d%d%d%d", &op, &x, &y, &c);
            if(op == 4) printf("%d\n", query(1, 1, n, x, y, c)%mod);
            else update(1, 1, n, op, x, y, c);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值