Hdu 4578 Transformation(区间加值,区间乘值,区间赋值,查询区间的p次方)

Transformation

Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)

Total Submission(s): 4145    Accepted Submission(s): 1027

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.

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

给你一个数组,初始值为零,有四种操作:(1)"1 x y c",代表 把区间 [x,y] 上的值全部加c。(2)"2 x y c",代表 把区间 [x,y] 上的值全部乘以c。(3)"3 x y c" 代表 把区间 [x,y]上的值全部赋值为c。

(4)"4 x y p" 代表 求区间 [x,y] 上值的p次方和1<=p<=3。

思路:

首先先解决一个区间内可能同时出现+和*的操作的问题(如果出现赋值,则在赋值之前的+和*都是无效的),我们可以把加法累计起来,把乘法先处理了,比如说原来[l,r]这一段上有了+x,现在要求*y,我们可以先把原来的每个数乘以y,然后加上x*y,即都是先处理乘法,在处理加法。

然后处理一下区间查询的问题,假设原来的值是k,如果是乘法或者赋值的话,sumv1,sumv2,sumv3的修改是很容易实现的,如果是加,(p+k)^3=p^3+3*p^2*k+3*k^2*p+k^3,所以sumv3[rt]=sumv3[rt]+sumv2[rt]*3*k+sumv1[rt]*3*k+(r-l+1)*k^3,同理二次方的修改也是如此

#include<bits/stdc++.h>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxn=110100;
typedef long long ll;
const int MOD=10007;
ll sumv1[maxn*4],sumv2[maxn*4],sumv3[maxn*4],v,op,setv[maxn*4],mul[4*maxn],addv[4*maxn];
int L,R;

void build(int l,int r,int rt){
    sumv1[rt]=0,sumv2[rt]=0,sumv3[rt]=0;
    setv[rt]=addv[rt]=mul[rt]=0;
    if(l==r)
        return ;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
}

void pushup(int rt){
     sumv1[rt]=(sumv1[rt<<1]+sumv1[rt<<1|1])%MOD;
     sumv2[rt]=(sumv2[rt<<1]+sumv2[rt<<1|1])%MOD;
     sumv3[rt]=(sumv3[rt<<1]+sumv3[rt<<1|1])%MOD;
}

void change(int op,int rt,int l,int r,ll k){
    if(op==1){
        sumv3[rt]=(sumv3[rt]+sumv2[rt]*3*k+3*k*k*sumv1[rt]%MOD+k*k*k%MOD*(r-l+1))%MOD;
        sumv2[rt]=(sumv2[rt]+k*k*(r-l+1)+2*k*sumv1[rt])%MOD;
        sumv1[rt]=(sumv1[rt]+k*(r-l+1))%MOD;
    }
    else if(op==2){
        sumv3[rt]=sumv3[rt]*(k*k*k%MOD)%MOD;
        sumv2[rt]=sumv2[rt]*k*k%MOD;
        sumv1[rt]=sumv1[rt]*k%MOD;
    }
    else{
        sumv3[rt]=(k*k*k%MOD)*(r-l+1)%MOD;
        sumv2[rt]=k*k*(r-l+1)%MOD;
        sumv1[rt]=k*(r-l+1)%MOD;
    }
}

void pushdown(int rt,int l,int r){
    if(setv[rt]!=0){
        int mid=(l+r)>>1;
        change(3,rt<<1,l,mid,setv[rt]);
        change(3,rt<<1|1,mid+1,r,setv[rt]);
        setv[rt<<1]=setv[rt<<1|1]=setv[rt];
        addv[rt<<1]=addv[rt<<1|1]=0;
        mul[rt<<1]=mul[rt<<1|1]=0;
        setv[rt]=0;
    }
    if(mul[rt]!=0){
        int mid=(l+r)>>1;
        change(2,rt<<1,l,mid,mul[rt]);
        change(2,rt<<1|1,mid+1,r,mul[rt]);
        if(mul[rt<<1]==0)
            mul[rt<<1]=mul[rt];
        else
            mul[rt<<1]=mul[rt<<1]*mul[rt]%MOD;
        if(mul[rt<<1|1]==0)
            mul[rt<<1|1]=mul[rt];
        else
            mul[rt<<1|1]=mul[rt<<1|1]*mul[rt]%MOD;
        addv[rt<<1]=addv[rt<<1]*mul[rt]%MOD;
        addv[rt<<1|1]=addv[rt<<1|1]*mul[rt]%MOD;
        mul[rt]=0;
    }
    if(addv[rt]!=0){
        int mid=(l+r)>>1;
        change(1,rt<<1,l,mid,addv[rt]);
        change(1,rt<<1|1,mid+1,r,addv[rt]);
        addv[rt<<1]=(addv[rt<<1]+addv[rt])%MOD;
        addv[rt<<1|1]=(addv[rt<<1|1]+addv[rt])%MOD;
        addv[rt]=0;
    }
}

void update(int l,int r,int rt){
    if(L<=l&&R>=r){
        if(op==3){
            setv[rt]=v,mul[rt]=0,addv[rt]=0;
            change(op,rt,l,r,v);
        }
        else if(op==2){
            if(mul[rt]==0)
                mul[rt]=v;
            else
                mul[rt]=mul[rt]*v%MOD;
            addv[rt]=addv[rt]*v%MOD;
            change(op,rt,l,r,v);
        }
        else{
            addv[rt]=(addv[rt]+v)%MOD;
            change(op,rt,l,r,v);
        }
        return ;
    }
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    if(L<=mid)
        update(lson);
    if(R>mid)
        update(rson);
    pushup(rt);
}

ll query(int l,int r,int rt){
    if(L<=l&&R>=r){
        if(v==1)
            return sumv1[rt];
        if(v==2)
            return sumv2[rt];
        return sumv3[rt];
    }
    pushdown(rt,l,r);
    int mid=(l+r)>>1;
    ll ans=0;
    if(L<=mid)
        ans+=query(lson);
    if(R>mid)
        ans+=query(rson);
    return ans;
}

int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==0&&m==0)
            break;
        build(1,n,1);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%lld",&op,&L,&R,&v);
            if(op==4)
                printf("%lld\n",query(1,n,1)%MOD);
            else
                update(1,n,1);
        }
    }
    return 0;
}

时间: 2024-11-13 07:56:07

Hdu 4578 Transformation(区间加值,区间乘值,区间赋值,查询区间的p次方)的相关文章

hdu 4578 Transformation

http://acm.hdu.edu.cn/showproblem.php?pid=4578 又做了一道好题.. 有三种操作: 1 a b c [a,b]加上c 2 a b c [a,b]乘上c 3 a b c [a,b]变为c 4 a b c 求[a,b]的c次方和(1<=c<=3) 这题首先需要解决的第一个问题是加上或乘上一个数对这个区间的c次方和分别产生什么改变,很简单,一化简就能得到. 第二个问题是当一段区间上既有乘又有加的lazy时应该怎么向下推送,因为一段区间上只能有一个lazy,

HDU 4578 Transformation (线段树区间多种更新)

http://acm.hdu.edu.cn/showproblem.php?pid=4578 题目大意:对于一个给定序列,序列内所有数的初始值为0,有4种操作.1:区间(x, y)内的所有数字全部加上C:2:区间(x, y)内所有数字全部乘C; 3:区间(x, y)内的所有数字全部重置为C: 4:输出区间(x, y)内所有数字的P次方的和.由于题目为多实例(至少10组样例),故很耿直的更新到叶子节点明显会TLE:因此需优化.可发现题目所有操作都是对区间进行,因此只需要更新 到区间内数字相同即可.

HDU 4578 - 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

HDU 4578 Transformation --线段树,好题

题意: 给一个序列,初始全为0,然后有4种操作: 1. 给区间[L,R]所有值+c 2.给区间[L,R]所有值乘c 3.设置区间[L,R]所有值为c 4.查询[L,R]的p次方和(1<=p<=3) 解法: 线段树,维护三个标记,addmark,mulmark,setmark分别表示3种更新,然后p[1],p[2],p[3]分别表示该节点的1,2,3次方和.标记传递顺序setmark一定是第一个,因为setmark可以使mulmark,addmark都失效还原,mulmark和addmark的顺

hdu 4578 Transformation(线段树)

Transformation Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others)Total Submission(s): 3084    Accepted Submission(s): 749 Problem Description Yuanfang is puzzled with the question below: There are n integers, a1, a2,

!SPOJ 1043 多次查询区间最大连续和-线段树

题意:已知一个数列,现在有多次查询(a,b),查询区间[a,b]的最大连续和. 分析: 这道题没有更新操作,只有区间查询操作.动态在于待查询区间不同,最大连续和也不同.所以其实相当于每次查询的时候要计算一次待查询区间的最大连续和. 有3种情况: 1.待查询区间包含当前区间.那么就直接返回当前区间的最大连续和: 2.待查询区间在当前区间的左区间或右区间.那么在左或右区间递归查询即可: 3.待查询区间横跨当前区间的左右区间.那么:当前区间在左区间部分的最大连续和.在右区间部分的最大连续和.左右区间连

算法模板——线段树4(区间加+区间乘+区间覆盖值+区间求和)

实现功能——1:区间加法 2:区间乘法 3:区间覆盖值 4:区间求和 这是个四种常见线段树功能的集合版哦...么么哒(其实只要协调好三种tag的关系并不算太难——前提是想明白了线段树的工作模式) 代码长度几经修改后也大为缩水 还有!!!——通过BZOJ1798反复的尝试,我的出来一个重要结论——尽量减少pushup操作的不必要使用次数,对于程序提速有明显的效果!!! 1 type vet=record 2 a0,a1:longint; 3 end; 4 var 5 i,j,k,l,m,n,a1,

HDU 4578 线段树区间更新(确定区间操作的优先级)

HDU 4578 线段树区间更新 操作有: 区间所有数add(c) 区间所有数mul(c) 区间所有数set(c) 查询有: 区间所有数的p次方和(p>= 1 && p <= 3) 关键是区间更新的三种操作的优先级的确定清楚set>mul>add 关键是:down和update中对区间的更新操作是一回事,可以写成函数方便编程 //#pragma warning (disable: 4786) //#pragma comment (linker, "/STA

[用CDQ分治解决区间加&amp;区间求和]【习作】

[前言] 作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢 于是,用CDQ分治解决区间加&区间求和这篇习作应运而生 [Part.I]区间加&区间求和的数据结构做法 [一]线段树 裸题... 1141ms #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include