HDU4578 Transformation(线段树)

/**
    有3种改变操作,需要3个lazy来记录;
    每种操作之间有优先关系
    change>mul>add;
    传递时按优先关系进行
    记录p= 1 2 3使得sum即可
    注意取模
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<set>


#define lson l,mid,now<<1
#define rson mid+1,r,now<<1|1
#define ls now<<1
#define rs now<<1|1
#define all left,right,k

#define inf 0x3f3f3f3f
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))


const int maxn=1e5+10;
const int mod=10007;

using namespace std;

ll tree[4*maxn][4],add[4*maxn],mul[4*maxn],ch[4*maxn];
///   数            lazy加      lazy乘       lazy替换

void built(int l,int r,int now)
{
    int mid=(l+r)>>1;
    add[now]=ch[now]=0;
    mul[now]=1;
    tree[now][1]=tree[now][2]=tree[now][3]=0;
    if(l==r) return ;
    built(lson);
    built(rson);
}

void pushup(int now)
{
    for(int i=1;i<=3;i++)
        tree[now][i]=(tree[ls][i]+tree[rs][i])%mod;
}

void pushdown(int l,int r,int now)
{
    int mid=(l+r)>>1;
    if(ch[now]!=0)///如果发生替换
    {
        ///改变ls rs的值 直接计算即可
        tree[ls][1]=(ch[now]*(mid-l+1))%mod;
        tree[ls][2]=((ch[now]*ch[now])%mod*(mid-l+1))%mod;
        tree[ls][3]=(((ch[now]*ch[now])%mod*ch[now])%mod)*(mid-l+1);

        tree[rs][1]=(ch[now]*(r-mid))%mod;
        tree[rs][2]=((ch[now]*ch[now])%mod*(r-mid))%mod;
        tree[rs][3]=(((ch[now]*ch[now])%mod*ch[now])%mod)*(r-mid);

        ///将ch传递 ls rs之前未传递的+*清零
        ch[ls]=ch[rs]=ch[now];
        add[ls]=add[rs]=ch[now]=0;
		mul[ls]=mul[rs]=1;
    }

    if(mul[now]!=1)///乘法
    {
        ///mul 传递乘法分配
        add[ls]=(add[ls]*mul[now])%mod;
        add[rs]=(add[rs]*mul[now])%mod;
        mul[ls]=(mul[ls]*mul[now])%mod;
        mul[rs]=(mul[rs]*mul[now])%mod;

        tree[ls][1]=(tree[ls][1]*mul[now])%mod;
        tree[ls][2]=((tree[ls][2]*mul[now])%mod*mul[now])%mod;
        tree[ls][3]=(((tree[ls][3]*mul[now])%mod*mul[now])%mod*mul[now])%mod;

		tree[rs][1]=(tree[rs][1]*mul[now])%mod;
        tree[rs][2]=((tree[rs][2]*mul[now])%mod*mul[now])%mod;
        tree[rs][3]=(((tree[rs][3]*mul[now])%mod*mul[now])%mod*mul[now])%mod;

        mul[now]=1;
    }

    if(add[now]!=0)///加法
    {
        add[ls]=(add[ls]+add[now])%mod;
        add[rs]=(add[rs]+add[now])%mod;
        ///(a+b)^2=a^2+2ab+b^2;
        ///累加一下 得到(a1+b)^2+...+(an+b)^2=(a1^2+..+an^2)+2*(a1+..+an)*b+(1+...+n)b^2;
        ///同理可以得到(a+b)^3;
        
        
        tree[ls][3]=(tree[ls][3]+(tree[ls][2]*add[now]*3)%mod+((add[now]*add[now])%mod*tree[ls][1]*3)%mod+((add[now]*add[now])%mod*add[now])%mod*(mid-l+1))%mod;
        tree[ls][2]=(tree[ls][2]+(tree[ls][1]*add[now]*2)%mod+(add[now]*add[now])%mod*(mid-l+1))%mod;
        tree[ls][1]=(tree[ls][1]+add[now]*(mid-l+1)%mod)%mod;

        tree[rs][3]=(tree[rs][3]+(tree[rs][2]*add[now]*3)%mod+((add[now]*add[now])%mod*tree[rs][1]*3)%mod+((add[now]*add[now])%mod*add[now]%mod)*(r-mid))%mod;
        tree[rs][2]=(tree[rs][2]+(tree[rs][1]*add[now]*2)%mod+(add[now]*add[now])%mod*(r-mid))%mod;
        tree[rs][1]=(tree[rs][1]+add[now]*(r-mid)%mod)%mod;

        add[now]=0;
    }
}

void updata(int l,int r,int now,int left,int right,int k,int cmd)
{
    int mid=(l+r)>>1,len=r-l+1;
    if(left<=l&&r<=right)
    {
        if(cmd==1)
        {
            add[now]=(add[now]+k)%mod;
            tree[now][3]=(tree[now][3]+((tree[now][2]*k)%mod*3)%mod+(((tree[now][1]*k)%mod*k)%mod*3)%mod+(((len*k)%mod*k)%mod*k)%mod)%mod;
            ///裂项展开相加
            tree[now][2]=(tree[now][2]+((tree[now][1]*k)%mod*2)%mod+((len*k)%mod*k)%mod)%mod;

            tree[now][1]=(tree[now][1]+(k*len)%mod)%mod;
        }
        if(cmd==2)
        {
            add[now]=(add[now]*k)%mod;
            mul[now]=(mul[now]*k)%mod;

            tree[now][1]=(tree[now][1]*k)%mod;
            tree[now][2]=((tree[now][2]*k)%mod*k)%mod;
            tree[now][3]=(((tree[now][3]*k)%mod*k)%mod*k)%mod;
        }
        if(cmd==3)
        {
            ///如果是替换操作 将当前值改变
            ///还要将之前为传递的+*操作标记清掉
            ch[now]=k%mod;
            add[now]=0;
            mul[now]=1;

            tree[now][1]=(k*len)%mod;
            tree[now][2]=((k*k)%mod*len)%mod;
            tree[now][3]=(((k*k)%mod*k)%mod*len)%mod;
        }
        return ;
    }
    if(add[now]!=0||mul[now]!=1||ch[now]!=0)
        pushdown(l,r,now);
    if(left<=mid) updata(lson,all,cmd);
    if(right>mid) updata(rson,all,cmd);
    pushup(now);
}

int query(int l,int r,int now,int left,int right,int k)
{
    int mid=(l+r)>>1;
    if(left<=l&&r<=right)
    {
        return tree[now][k];
    }
    if(add[now]!=0||mul[now]!=1||ch[now]!=0)
        pushdown(l,r,now);
    int ans=0;
    if(left<=mid) ans+=query(lson,all);
    if(right>mid) ans+=query(rson,all);
    return ans%mod;
}

int main(){
    int n,m;
    while(scanf("%d%d",&n,&m))
    {
        if(n+m==0) break;
        int cmd,l,r,k;
        built(1,n,1);
        while(m--)
        {
            scanf("%d%d%d%d",&cmd,&l,&r,&k);
            if(cmd==4)
                printf("%d\n",query(1,n,1,l,r,k));
            else
                updata(1,n,1,l,r,k,cmd);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值