HDU 4578——Transformation

Transformation

Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)
Total Submission(s): 5927    Accepted Submission(s): 1472


Problem Description
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
 

Source

题意:
n个数初始为0,m个操作
操作分4种:
1 x y c x到y的所有数加c
2 x y c x到y的所有数乘c
3 x y c x到y的所有数变成c
4 x y p 求x到y的所有数的p次方的和 (1<=p<=3)

分析:
我们假设x到y的和为a,,x到y的平方的和为b,x到y的次方的和为d那么:
操作1过后 d=d+3*c*b+3*c*c*a+c*c*c*(y-x+1)     通过两个数的次方和推导:(x1+c)^3+(x2+c)^3=x1^3+x2^3+3*c*(x1^2+x2^2)+3*c*c*(x1+x2)+c^3*2
                    b=b+2*c*a+c*c*(y-x+1)         通过两个数的平方和推导   (x1+c)^2+(x2+c)^2=x1^2+x2^2+2*c*(x1+x2)+c^2*2
                    a=a+c*(y-x+1) 
ps:因为d的推导要用到a,b   b的推导要用到a所以每一次需要先算次方,再算平方,最后算普通和
操作2过后 a=a*c
                   b=b*c*c
                   d=d*c*c*c
操作3过后 a=c*(y-x+1)
                   b=c*c*(y-x+1)
                   d=c*c*c*(y-x+1)

可以看到,普通和,平方和,次方和的变化都与变化之前的三种和有关系,所以只存普通和会给求平方和与次方和造成不方便,所以我们把3个值一起存,一起更新。
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#define INF 0x3f3f3f3f
#define EXP 0.00000001
#define MOD 10007
#define MAXN 100005
#define ltree 2*id,ll,mid
#define rtree 2*id+1,mid+1,rr
#define FO(i,n,m) for(int i=n;i<=m;++i)
#define mem(a) memset(a,0,sizeof(a))
typedef long long LL;

using namespace std;

int n,m;
int add[4*MAXN];
int mul[4*MAXN];
int ch[4*MAXN];
int tree1[4*MAXN],tree2[4*MAXN],tree3[4*MAXN];

void Pushup(int id)
{
    tree1[id]=(tree1[2*id]+tree1[2*id+1])%MOD;
    tree2[id]=(tree2[2*id]+tree2[2*id+1])%MOD;
    tree3[id]=(tree3[2*id]+tree3[2*id+1])%MOD;
}

void Pushdown(int id,int ll,int rr)
{
    int llen=(ll+rr)/2-ll+1;
    int rlen=rr-(ll+rr)/2;
    int lt=2*id,rt=2*id+1;
    if(ch[id])
    {
        ch[lt]=ch[rt]=ch[id];
        add[lt]=add[rt]=0;
        mul[lt]=mul[rt]=1;
        tree1[lt]=ch[id]*llen%MOD;
        tree2[lt]=ch[id]*ch[id]%MOD*llen%MOD;
        tree3[lt]=ch[id]*ch[id]%MOD*ch[id]%MOD*llen%MOD;
        tree1[rt]=ch[id]*rlen%MOD;
        tree2[rt]=ch[id]*ch[id]%MOD*rlen%MOD;
        tree3[rt]=ch[id]*ch[id]%MOD*ch[id]%MOD*rlen%MOD;
        ch[id]=0;
    }
    if(mul[id]!=1)
    {
        mul[lt]=mul[lt]*mul[id]%MOD;
        mul[rt]=mul[rt]*mul[id]%MOD;
        add[lt]=add[lt]*mul[id]%MOD;
        add[rt]=add[rt]*mul[id]%MOD;
        tree1[lt]=tree1[lt]*mul[id]%MOD;
        tree2[lt]=tree2[lt]*mul[id]%MOD*mul[id]%MOD;
        tree3[lt]=tree3[lt]*mul[id]%MOD*mul[id]%MOD*mul[id]%MOD;
        tree1[rt]=tree1[rt]*mul[id]%MOD;
        tree2[rt]=tree2[rt]*mul[id]%MOD*mul[id]%MOD;
        tree3[rt]=tree3[rt]*mul[id]%MOD*mul[id]%MOD*mul[id]%MOD;
        mul[id]=1;
    }
    if(add[id])
    {
        add[lt]=(add[lt]+add[id])%MOD;
        add[rt]=(add[rt]+add[id])%MOD;
        tree3[lt]=(tree3[lt]+3*add[id]*tree2[lt]%MOD+3*add[id]*add[id]%MOD*tree1[lt]%MOD+add[id]*add[id]%MOD*add[id]%MOD*llen%MOD)%MOD;
        tree2[lt]=(tree2[lt]+2*add[id]*tree1[lt]%MOD+add[id]*add[id]%MOD*llen%MOD)%MOD;
        tree1[lt]=(tree1[lt]+add[id]*llen%MOD)%MOD;
        tree3[rt]=(tree3[rt]+3*add[id]*tree2[rt]%MOD+3*add[id]*add[id]%MOD*tree1[rt]%MOD+add[id]*add[id]%MOD*add[id]%MOD*rlen%MOD)%MOD;
        tree2[rt]=(tree2[rt]+2*add[id]*tree1[rt]%MOD+add[id]*add[id]%MOD*rlen%MOD)%MOD;
        tree1[rt]=(tree1[rt]+add[id]*rlen%MOD)%MOD;
        add[id]=0;
    }
}

void Build(int id,int ll,int rr)
{
    add[id]=0;
    mul[id]=1;
    ch[id]=0;
    if(ll==rr)
    {
        tree1[id]=0;
        tree2[id]=0;
        tree3[id]=0;
        return;
    }
    int mid=(ll+rr)/2;
    Build(ltree);
    Build(rtree);
    Pushup(id);
}

void Update(int id,int ll,int rr,int x,int y,int op,int c)
{
    if(x<=ll&&rr<=y)
    {
        if(op==1)
        {
            add[id]=(add[id]+c)%MOD;
            tree3[id]=(tree3[id]+3*c*tree2[id]%MOD+3*c*c%MOD*tree1[id]%MOD+c*c%MOD*c%MOD*(rr-ll+1)%MOD)%MOD;
            tree2[id]=(tree2[id]+2*c*tree1[id]%MOD+c*c%MOD*(rr-ll+1)%MOD)%MOD;
            tree1[id]=(tree1[id]+c*(rr-ll+1)%MOD)%MOD;
            return;
        }
        if(op==2)
        {
            mul[id]=mul[id]*c%MOD;
            add[id]=add[id]*c%MOD;
            tree1[id]=tree1[id]*c%MOD;
            tree2[id]=tree2[id]*c%MOD*c%MOD;
            tree3[id]=tree3[id]*c%MOD*c%MOD*c%MOD;
            return;
        }
        if(op==3)
        {
            add[id]=0;
            mul[id]=1;
            ch[id]=c;
            tree1[id]=c*(rr-ll+1)%MOD;
            tree2[id]=c*c%MOD*(rr-ll+1)%MOD;
            tree3[id]=c*c%MOD*c%MOD*(rr-ll+1)%MOD;
            return;
        }
    }
    Pushdown(id,ll,rr);
    int mid=(ll+rr)/2;
    if(y<=mid)
        Update(ltree,x,y,op,c);
    else if(x>mid)
        Update(rtree,x,y,op,c);
    else
    {
        Update(ltree,x,mid,op,c);
        Update(rtree,mid+1,y,op,c);
    }
    Pushup(id);
}

int Query(int id,int ll,int rr,int x,int y,int pow)
{
    if(x<=ll&&rr<=y)
    {
        if(pow==1)
            return tree1[id];
        if(pow==2)
            return tree2[id];
        if(pow==3)
            return tree3[id];
    }
    Pushdown(id,ll,rr);
    int mid=(ll+rr)/2;
    if(y<=mid)
        return Query(ltree,x,y,pow);
    else if(x>mid)
        return Query(rtree,x,y,pow);
    else
        return (Query(ltree,x,mid,pow)+Query(rtree,mid+1,y,pow))%MOD;
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)
            break;
        Build(1,1,n);
        while(m--)
        {
            int op,x,y,c;
            scanf("%d%d%d%d",&op,&x,&y,&c);
            if(op==4)
                printf("%d\n",Query(1,1,n,x,y,c));
            else
                Update(1,1,n,x,y,op,c);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值