HDU 4578 Transformation 线段树 区间加法 区间乘法 区间置数 维护区间和 区间平方和 区间立方和

http://acm.hdu.edu.cn/showproblem.php?pid=4578

Yuanfang is puzzled with the question below:
There are n integers, a 1, a 2, …, a n. The initial values of them are 0. There are four kinds of operations.
Operation 1: Add c to each number between a x and a y inclusive. In other words, do transformation a k<---a k+c, k = x,x+1,…,y.
Operation 2: Multiply c to each number between a x and a y inclusive. In other words, do transformation a k<---a k×c, k = x,x+1,…,y.
Operation 3: Change the numbers between a x and a y to c, inclusive. In other words, do transformation a k<---c, k = x,x+1,…,y.
Operation 4: Get the sum of p power among the numbers between a x and a y inclusive. In other words, get the result of a x p+a x+1 p+…+a y p.
Yuanfang has no idea of how to do it. So he wants to ask you to help him.

Input

There are no more than 10 test cases.
For each case, the first line contains two numbers n and m, meaning that there are n integers and m operations. 1 <= n, m <= 100,000.
Each the following m lines contains an operation. Operation 1 to 3 is in this format: "1 x y c" or "2 x y c" or "3 x y c". Operation 4 is in this format: "4 x y p". (1 <= x <= y <= n, 1 <= c <= 10,000, 1 <= p <= 3)
The input ends with 0 0.

Output

For each operation 4, output a single integer in one line representing the result. The answer may be quite large. You just need to calculate the remainder of the answer when divided by 10007.

Sample Input

5 5
3 3 5 7
1 2 4 4
4 1 5 2
2 2 5 8
4 3 5 3
0 0

Sample Output

307
7489

题目大意:n个数m个操作,n个数的初始值均为0,有四种操作:(1)区间加法;(2)区间乘法;(3)区间置数;(4)输出区间的和或者平方和或者立方和

思路:四种操作单拆开来,都不难,合到一起,就是恶心。区间和容易维护,那区间平方和和立方和呢?看图:

区间平方和的维护:

 

 顺带提一下区间方差的维护:

 不要问立方和怎么维护,同平方和,展开立方式再化简就好了。

题目涉及到三个区间修改操作,因此需要三个lazy标记。修改置数标记的时候,要同时把另外两个标记初始化,修改乘法标记的时候,还要修改加法标记。这在每个update函数和pushdown函数都有体现,不太明白的可以看下代码。注意区间和、平方和、立方和的维护是有顺序的,当然可以像我一样用中间变量记录一下。其他的就是细节问题了,没什么好说的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

const ll MOD=1e4+7;
const int maxl=1e5;

struct node
{
	int l,r;
	ll lazy1,lazy2,lazy3;
	ll sum[3];
};

node tree[maxl*4+5];
int n,m;

void build(int i,int l,int r)//i为当前节点编号 区间为[l,r]
{
	tree[i].l=l,tree[i].r=r;
	tree[i].lazy1=0;
    tree[i].sum[0]=tree[i].sum[1]=tree[i].sum[2]=0;
    tree[i].lazy2=1;
    tree[i].lazy3=INF;
	if(l==r)//叶子节点
		return ;
	int mid=(l+r)>>1;
	build(i<<1,l,mid);//左子树
	build(i<<1|1,mid+1,r);//右子树
}

inline void check(int i)
{
    for(int j=0;j<3;j++)
        if(tree[i].sum[j]>=MOD)
            tree[i].sum[j]%=MOD;
    if(tree[i].lazy1>=MOD)
        tree[i].lazy1%=MOD;
    if(tree[i].lazy2>=MOD)
        tree[i].lazy2%=MOD;
    if(tree[i].lazy3>=MOD&&tree[i].lazy3!=INF)
        tree[i].lazy3%=MOD;
}

inline void down3(int i)//区间置数
{
    int l=i<<1,r=i<<1|1;
    tree[l].lazy3=tree[r].lazy3=tree[i].lazy3;
    tree[l].lazy2=tree[r].lazy2=1;
    tree[l].lazy1=tree[r].lazy1=0;
    int len1=tree[l].r-tree[l].l+1;
    int len2=tree[r].r-tree[r].l+1;
    ll v=tree[i].lazy3%MOD;
    ll v1=tree[l].sum[0]=len1*v%MOD;
    tree[l].sum[1]=v1*v%MOD;
    tree[l].sum[2]=v1*v*v%MOD;
    ll v2=tree[r].sum[0]=len2*v;
    tree[r].sum[1]=v2*v%MOD;
    tree[r].sum[2]=v2*v*v%MOD;
    tree[i].lazy3=INF;
}

inline void down2(int i)//区间乘法
{
    int l=i<<1,r=i<<1|1;
    ll v=tree[i].lazy2;
    tree[l].lazy2=tree[l].lazy2*v%MOD;
    tree[r].lazy2=tree[r].lazy2*v%MOD;
    tree[l].lazy1=tree[l].lazy1*v%MOD;
    tree[r].lazy1=tree[r].lazy1*v%MOD;
    tree[l].sum[0]=tree[l].sum[0]*v%MOD;
    tree[l].sum[1]=tree[l].sum[1]*v*v%MOD;
    tree[l].sum[2]=(tree[l].sum[2]*v*v%MOD)*v%MOD;
    tree[r].sum[0]=tree[r].sum[0]*v%MOD;
    tree[r].sum[1]=tree[r].sum[1]*v*v%MOD;
    tree[r].sum[2]=(tree[r].sum[2]*v*v%MOD)*v%MOD;
    tree[i].lazy2=1;
}

inline void down1(int i)//区间加法
{
    int l=i<<1,r=i<<1|1;
    int len1=tree[l].r-tree[l].l+1;
    int len2=tree[r].r-tree[r].l+1;
    ll v=tree[i].lazy1%MOD;
    tree[l].lazy1+=v;
    tree[r].lazy1+=v;
    ll t1=tree[l].sum[0]%MOD;
    ll t2=tree[l].sum[1]%MOD;
    tree[l].sum[0]+=len1*v;
    tree[l].sum[1]+=2*v*t1+len1*v*v;
    tree[l].sum[2]+=3*v*v*t1%MOD+3*v*t2%MOD+(len1*v*v%MOD)*v%MOD;
    t1=tree[r].sum[0]%MOD;
    t2=tree[r].sum[1]%MOD;
    tree[r].sum[0]+=len2*v;
    tree[r].sum[1]+=2*v*t1+len2*v*v;
    tree[r].sum[2]+=3*v*v*t1%MOD+3*v*t2%MOD+(len2*v*v%MOD)*v%MOD;
    check(l);
    check(r);
    tree[i].lazy1=0;
}

inline void up(int i)
{
    int l=i<<1,r=i<<1|1;
    tree[i].sum[0]=tree[l].sum[0]+tree[r].sum[0];
    tree[i].sum[1]=tree[l].sum[1]+tree[r].sum[1];
    tree[i].sum[2]=tree[l].sum[2]+tree[r].sum[2];
    check(i);
}

void update1(int i,int l,int r,ll v)//加法
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        int len=tree[i].r-tree[i].l+1;
        ll t1=tree[i].sum[0]%MOD;
        ll t2=tree[i].sum[1]%MOD;
        tree[i].lazy1+=v;
        tree[i].sum[0]+=len*v;
        tree[i].sum[1]+=2*v*t1+len*v*v;
        tree[i].sum[2]+=3*v*v*t1%MOD+3*v*t2%MOD+(len*v*v%MOD)*v;
        check(i);
        return ;
    }
    check(i);
    if(tree[i].lazy3!=INF)
        down3(i);
    if(tree[i].lazy2!=1)
        down2(i);
    if(tree[i].lazy1)
        down1(i);
	int mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)
        update1(i<<1,l,r,v);
    else if(l>mid)
        update1(i<<1|1,l,r,v);
    else
        update1(i<<1,l,mid,v),
        update1(i<<1|1,mid+1,r,v);
    up(i);
}

void update2(int i,int l,int r,ll v)//乘法
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        tree[i].lazy1*=v;
        tree[i].lazy2*=v;
        tree[i].sum[0]*=v%MOD;
        tree[i].sum[1]*=v*v%MOD;
        tree[i].sum[2]*=v*v*v%MOD;
        check(i);
        return ;
    }
    check(i);
    if(tree[i].lazy3!=INF)
        down3(i);
    if(tree[i].lazy2!=1)
        down2(i);
    if(tree[i].lazy1)
        down1(i);
	int mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)
        update2(i<<1,l,r,v);
    else if(l>mid)
        update2(i<<1|1,l,r,v);
    else
        update2(i<<1,l,mid,v),
        update2(i<<1|1,mid+1,r,v);
    up(i);
}

void update3(int i,int l,int r,ll v)//置数
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        int len=tree[i].r-tree[i].l+1;
        tree[i].lazy1=0;
        tree[i].lazy2=1;
        tree[i].lazy3=v;
        ll val=tree[i].sum[0]=len*v%MOD;
        tree[i].sum[1]=val*v%MOD;
        tree[i].sum[2]=val*v*v%MOD;
        check(i);
        return ;
    }
    check(i);
    if(tree[i].lazy3!=INF)
        down3(i);
    if(tree[i].lazy2!=1)
        down2(i);
    if(tree[i].lazy1)
        down1(i);
	int mid=(tree[i].l+tree[i].r)>>1;
	if(r<=mid)
        update3(i<<1,l,r,v);
    else if(l>mid)
        update3(i<<1|1,l,r,v);
    else
        update3(i<<1,l,mid,v),
        update3(i<<1|1,mid+1,r,v);
    up(i);
}

ll query(int i,int l,int r,int p)
{
	if(tree[i].l==l&&tree[i].r==r)//当前区间刚好是要找的区间
		return tree[i].sum[p];
    if(tree[i].lazy3!=INF)
        down3(i);
    if(tree[i].lazy2!=1)
        down2(i);
    if(tree[i].lazy1)
        down1(i);
	int mid=(tree[i].l+tree[i].r)>>1;
	ll ans;
	if(r<=mid)//要查询的区间在左半部分
		ans=query(i<<1,l,r,p);
	else if(l>mid)//要查询的区间在右半部分
		ans=query(i<<1|1,l,r,p);
	else //左右两边均有
		ans=query(i<<1,l,mid,p)+query(i<<1|1,mid+1,r,p);
    if(ans>=MOD)
        ans%=MOD;
    return ans;
}

int main()
{
    while(~scanf("%d %d",&n,&m)&&n)
    {
        build(1,1,n);
        int op,l,r;
        ll v;
        for(int i=0;i<m;i++)
        {
            scanf("%d %d %d %lld",&op,&l,&r,&v);
            if(op==1)
                update1(1,l,r,v);
            else if(op==2)
                update2(1,l,r,v);
            else if(op==3)
                update3(1,l,r,v);
            else
                printf("%lld\n",query(1,l,r,v-1)%MOD);
        }
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值