HDU4578 Transformation

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

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

题意:

	1.将a~b都加上c
	2.将a~b都乘上c
	3.将a~b都变成c
	4.查询a~b的每个数的p次方的和。(p=1,2,3)

思路:依次做了加+乘以及加+覆盖,才来做这道题,懒标记优先次序: s e t v &gt; m u l v &gt; a d d v setv&gt;mulv&gt;addv setv>mulv>addv,即后者是在前者的基础上的标记。直接在区间内维护1、2、3次方的sum即可。
更新和查询都是pushdown到目标区间。

#include<bits/stdc++.h>
using namespace std;
#define maxn (100000+100)
#define ll long long
#define M(x) (x%=10007)

int n,m;
ll op,ql,qr,val,_sum;

struct SegmentTree{

    ll sumv[maxn*4][4],addv[maxn*4],mulv[maxn*4],setv[maxn*4];

    void build(int o,int l,int r)
    {
        if(l==r)
        {
            for(int i=1;i<=3;i++)sumv[o][i]=0;
            setv[o]=0;addv[o]=0;mulv[o]=1;
        }
        else
        {
            int mid=(l+r)/2;
            build(o*2,l,mid);
            build(o*2+1,mid+1,r);
            setv[o]=-1;addv[o]=0;mulv[o]=1;
            for(int i=1;i<=3;i++)sumv[o][i]=0;
        }        
    }

    void pushdown(int o)
    {
        if(setv[o]>=0)
        {
            setv[o*2]=setv[o*2+1]=setv[o];
            addv[o*2]=addv[o*2+1]=0;
            mulv[o*2]=mulv[o*2+1]=1;
            setv[o]=-1;
        }
        if(mulv[o]>1)
        {
            addv[o*2]*=mulv[o];M(addv[o*2]);addv[o*2+1]*=mulv[o];M(addv[o*2+1]);
            mulv[o*2]*=mulv[o];mulv[o*2+1]*=mulv[o];M(mulv[o*2]);M(mulv[o*2+1]);
            mulv[o]=1;
        }
        if(addv[o]>0)
        {
            addv[o*2]+=addv[o];M(addv[o*2]);
            addv[o*2+1]+=addv[o];M(addv[o*2+1]);
            addv[o]=0;
        }
    }

    void maintain(int o,int l,int r)
    {
        if(l<r) for(int i=1;i<=3;i++)sumv[o][i]=sumv[o*2][i]+sumv[o*2+1][i],M(sumv[o][i]);
        else    for(int i=1;i<=3;i++)sumv[o][i]=0;

        if(setv[o]>=0)
        {
            sumv[o][1]=(r-l+1)*setv[o];
            sumv[o][2]=(r-l+1)*setv[o]*setv[o];
            sumv[o][3]=(r-l+1)*setv[o]*setv[o]*setv[o];
            for(int i=1;i<=3;i++)M(sumv[o][i]);
        }
        if(mulv[o]>1)
        {
            sumv[o][1]*=mulv[o];
            sumv[o][2]*=mulv[o]*mulv[o];
            sumv[o][3]*=mulv[o]*mulv[o]*mulv[o];
            for(int i=1;i<=3;i++)M(sumv[o][i]);
        }
        if(addv[o]>0)
        {
            int s1=sumv[o][1],s2=sumv[o][2];
            sumv[o][1]+=addv[o]*(r-l+1);
            sumv[o][2]+=2*s1*addv[o]+addv[o]*addv[o]*(r-l+1);
            sumv[o][3]+=3*addv[o]*addv[o]*s1+3*s2*addv[o]+addv[o]*addv[o]*addv[o]*(r-l+1);
            for(int i=1;i<=3;i++)M(sumv[o][i]);
        }
    }

    void update(int o,int l,int r)
    {
        if(ql<=l&&qr>=r)
        {
            if(op==1)addv[o]+=val;
            else if(op==2)mulv[o]*=val,addv[o]*=val;
            else setv[o]=val,addv[o]=0,mulv[o]=1;    
            M(addv[o]);M(mulv[o]);M(setv[o]);        
        }
        else
        {
            int mid=(l+r)/2;
            pushdown(o);
            maintain(o*2,l,mid);maintain(o*2+1,mid+1,r);
            if(ql<=mid)update(o*2,l,mid);
            if(qr>mid)update(o*2+1,mid+1,r);
        }
        maintain(o,l,r);    
    }

    void query(int o,int l,int r)
    {
        if(ql<=l&&qr>=r)_sum+=sumv[o][val],M(_sum);
        else
        {
            int mid=(l+r)/2;
            pushdown(o);
            maintain(o*2,l,mid);maintain(o*2+1,mid+1,r);
            maintain(o,l,r);
            if(ql<=mid)query(o*2,l,mid);
            if(qr>mid)query(o*2+1,mid+1,r);
        }    
    }

}tree;

int main()
{
	//freopen("input.in","r",stdin);
	while(cin>>n>>m&&n)
	{
		tree.build(1,1,n);
		while(m--)
		{
			scanf("%lld%lld%lld%lld",&op,&ql,&qr,&val);M(val);
			if(op!=4)tree.update(1,1,n);
			else 
			{
				_sum=0;
				tree.query(1,1,n);
				printf("%lld\n",_sum);
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值