HDU4578 线段树多种操作的实现

直接贴代码吧:
这题码量挺大的
最重要的学会面对多种运算不同的标记时应该如何处理他们之间的先后关系
以及对于求和时前后sum值之间的代数关系一定要写出来,便于理解

#include <bits/stdc++.h>
// 精品好题
using namespace std;
typedef long long ll;
const int MAXN = 1e5+7;
const int MOD = 10007;
ll add[MAXN<<2],se[MAXN<<2],mul[MAXN<<2];//add是加 set重置 mul乘 三种懒惰标记
ll sum1[MAXN<<2],sum2[MAXN<<2],sum3[MAXN<<2];//直接求和 平方和 立方和
// 多种操作时 要注意重置操作 优先级最高 重置之后 加等于0 乘等于1
// 在进行乘法操作时 如果当前有加法标记 那么加法标记也要相应的先乘以这个标记进行更新
// 而对于加法操作 因为涉及到平方和立方的操作 具体要推倒 新的节点与之前节点的值具有怎样的关系 关系找出来才能解决问题

void pushup(int rt)
{
	sum1[rt] = (sum1[rt<<1]+sum1[rt<<1|1])%MOD;
	sum2[rt] = (sum2[rt<<1]+sum2[rt<<1|1])%MOD;
	sum3[rt] = (sum3[rt<<1]+sum3[rt<<1|1])%MOD;
}

void build(int rt,int l,int r)
{
	add[rt] = se[rt] = 0;//都相当于一开始初始化操作
	mul[rt] = 1;
	if(l == r){
		sum1[rt] = sum2[rt] = sum3[rt] = 0;
		return ;
	}
	int mid = (l+r)>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}

void pushdown(int rt,int len)
{
	if(se[rt]){
		se[rt<<1] = se[rt<<1|1] = se[rt];
		add[rt<<1] = add[rt<<1|1] = 0;// 当碰到重置的时候 先将加的变为0 乘的要变为1
		mul[rt<<1] = mul[rt<<1|1] = 1;
		ll tmp = ((se[rt] * se[rt]) % MOD) * se[rt] % MOD;
        sum1[rt << 1] = ((len - (len >> 1)) % MOD) * (se[rt] % MOD) % MOD;
        sum1[rt << 1 | 1] = ((len >> 1) % MOD) * (se[rt] % MOD) % MOD;
        sum2[rt << 1] = ((len - (len >> 1)) % MOD) * ((se[rt] * se[rt]) % MOD) % MOD;
        sum2[rt << 1 | 1] = ((len >> 1) % MOD) * ((se[rt] * se[rt]) % MOD) % MOD;
        sum3[rt << 1] = ((len - (len >> 1)) % MOD) * tmp % MOD;
        sum3[rt << 1 | 1] = ((len >> 1) % MOD) * tmp % MOD;
        se[rt] = 0;	
    }
	if(mul[rt] != 1) {    //这个就是mul[rt] != 1 , 当时我这里没注意所以TLE了
        mul[rt << 1] = (mul[rt << 1] * mul[rt]) % MOD;
        mul[rt << 1 | 1] = (mul[rt << 1 | 1] * mul[rt]) % MOD;
        if(add[rt << 1])    //注意这个也要下放
            add[rt << 1] = (add[rt << 1] * mul[rt]) % MOD;
        if(add[rt << 1 | 1])
            add[rt << 1 | 1] = (add[rt << 1 | 1] * mul[rt]) % MOD;
        ll tmp = (((mul[rt] * mul[rt]) % MOD * mul[rt]) % MOD);
        sum1[rt << 1] = (sum1[rt << 1] * mul[rt]) % MOD;
        sum1[rt << 1 | 1] = (sum1[rt << 1 | 1] * mul[rt]) % MOD;
        sum2[rt << 1] = (sum2[rt << 1] % MOD) * ((mul[rt] * mul[rt]) % MOD) % MOD;
        sum2[rt << 1 | 1] = (sum2[rt << 1 | 1] % MOD) * ((mul[rt] * mul[rt]) % MOD) % MOD;
        sum3[rt << 1] = (sum3[rt << 1] % MOD) * tmp % MOD;
        sum3[rt << 1 | 1] = (sum3[rt << 1 | 1] % MOD) * tmp % MOD;
        mul[rt] = 1;
    }
	if(add[rt]) {
        add[rt << 1] += add[rt];    //add是+= , mul是*=
        add[rt << 1 | 1] += add[rt];
        ll tmp = (add[rt] * add[rt] % MOD) * add[rt] % MOD;        //注意sum3 , sum2 , sum1的先后顺序
        sum3[rt << 1] = (sum3[rt << 1] + (tmp * (len - (len >> 1)) % MOD) + 3 * add[rt] * ((sum2[rt << 1] + sum1[rt << 1] * add[rt]) % MOD)) % MOD;
        sum3[rt << 1 | 1] = (sum3[rt << 1 | 1] + (tmp * (len >> 1) % MOD) + 3 * add[rt] * ((sum2[rt << 1 | 1] + sum1[rt << 1 | 1] * add[rt]) % MOD)) % MOD;
        sum2[rt << 1] = (sum2[rt << 1] + ((add[rt] * add[rt] % MOD) * (len - (len >> 1)) % MOD) + (2 * sum1[rt << 1] * add[rt] % MOD)) % MOD;
        sum2[rt << 1 | 1] = (sum2[rt << 1 | 1] + (((add[rt] * add[rt] % MOD) * (len >> 1)) % MOD) + (2 * sum1[rt << 1 | 1] * add[rt] % MOD)) % MOD;
        sum1[rt << 1] = (sum1[rt << 1] + (len - (len >> 1)) * add[rt]) % MOD;
        sum1[rt << 1 | 1] = (sum1[rt << 1 | 1] + (len >> 1) * add[rt]) % MOD;
        add[rt] = 0;
    }
}

void update(int rt,int l,int r,int ul,int ur,int k,int c)
{
	 if(ul <= l && ur >= r) {
        if(k == 3) {
            se[rt] = c;
            add[rt] = 0;
            mul[rt] = 1;
            sum1[rt] = ((r - l + 1) * c) % MOD;
            sum2[rt] = ((r - l + 1) * ((c * c) % MOD)) % MOD;
            sum3[rt] = ((r - l + 1) * (((c * c) % MOD) * c % MOD)) % MOD;
        } else if(k == 2) {
            mul[rt] = (mul[rt] * c) % MOD;
            if(add[rt])
                add[rt] = (add[rt] * c) % MOD;
            sum1[rt] = (sum1[rt] * c) % MOD;
            sum2[rt] = (sum2[rt] * (c * c % MOD)) % MOD;
            sum3[rt] = (sum3[rt] * ((c * c % MOD) * c % MOD)) % MOD;
        } else if(k == 1) {
            add[rt] += c;
            ll tmp = (((c * c) % MOD * c) % MOD * (r - l + 1)) % MOD;    //(r - l + 1) * c^3
            sum3[rt] = (sum3[rt] + tmp + 3 * c * ((sum2[rt] + sum1[rt] * c) % MOD)) % MOD;
            sum2[rt] = (sum2[rt] + (c * c % MOD * (r - l + 1) % MOD) + 2 * sum1[rt] * c) % MOD;
            sum1[rt] = (sum1[rt] + (r - l + 1) * c) % MOD;
        }
        return ;
    }
	pushdown(rt,r-l+1);
	int mid = (l+r)>>1;
	if(ul <= mid) update(rt<<1,l,mid,ul,ur,k,c);
	if(ur > mid) update(rt<<1|1,mid+1,r,ul,ur,k,c);
	pushup(rt);
}

ll query(int rt,int l,int r,int ql,int qr,int q)
{
	if(l>=ql&&r<=qr){
		if(q==1)
			return sum1[rt];
		else if(q==2)
			return sum2[rt];
		else
			return sum3[rt];
	}
	pushdown(rt,r-l+1);
	int mid = (l+r)>>1;
	ll ans = 0;
	if(ql <= mid) ans += query(rt<<1,l,mid,ql,qr,q);
	if(qr > mid) ans += query(rt<<1|1,mid+1,r,ql,qr,q); 
	return ans%MOD;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值