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, …, 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

写得比较恶心。。因为 p <= 3 , 所以处理好3个sum值 。

push_down要写得优美才可以过

至于,过程中那些 + 与 * 的操作的话只是需要把 n 方公式分解好就可以了。

比如 说 ( c * a + b )^ 3 = (c*a)^3 + 3*(c*a)^2*b + 3*(a*c)*b^2 + b^3 .

    那么平方 , 一次的操作也是这么进行

至于操作3的话就是直接把 操作1跟操作2的lazy清空掉就可以了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstring>
#include <map>
#include <queue>
using namespace std;
typedef long long LL ;
typedef pair<int,int> pii ;
#define X first
#define Y second
#define root 1,n,1
#define lr rt<<1
#define rr rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N = 200010;
const int mod = 10007;

int sum1[N<<2] , sum2[N<<2] , sum3[N<<2] , lazy1[N<<2] , lazy2[N<<2] , lazy3[N<<2];
int n , m ;
void build( int l , int r , int rt ) {
    sum1[rt] = sum2[rt] = sum3[rt] = 0 ;
    lazy1[rt] = lazy3[rt] = 0 ;   // add  and clean
    lazy2[rt] = 1 ;                 // muti
    if( l == r ) return ;
    int mid = (l+r)>>1;
    build(lson) , build(rson);
}

void Up( int rt ) {
    sum1[rt] = ( sum1[lr] + sum1[rr] ) % mod ;
    sum2[rt] = ( sum2[lr] + sum2[rr] ) % mod ;
    sum3[rt] = ( sum3[lr] + sum3[rr] ) % mod ;
}

void Down( int l , int r , int rt ) {
    if( l == r ) return ;
    int mid = (l+r)>>1;
    if( lazy3[rt] != 0 ) {
        lazy3[lr] = lazy3[rr] = lazy3[rt] ;
        lazy1[lr] = lazy1[rr] = 0 ;
        lazy2[lr] = lazy2[rr] = 1 ;
        sum1[lr] = ( mid - l + 1 ) * lazy3[rt] % mod ;
        sum2[lr] = ( mid - l + 1 ) * lazy3[rt] % mod * lazy3[rt] % mod ;
        sum3[lr] = ( mid - l + 1 ) * lazy3[rt] % mod * lazy3[rt] % mod * lazy3[rt] % mod ;
        sum1[rr] = ( r - mid ) * lazy3[rt] % mod ;
        sum2[rr] = ( r - mid ) * lazy3[rt] % mod * lazy3[rt] % mod ;
        sum3[rr] = ( r - mid ) * lazy3[rt] % mod * lazy3[rt] % mod * lazy3[rt] % mod ;
        lazy3[rt] = 0 ;
    }
    if( lazy1[rt] != 0 || lazy2[rt] != 1 ) {
        lazy1[lr] = ( lazy1[lr] * lazy2[rt] % mod + lazy1[rt] ) % mod ;
        lazy2[lr] = lazy2[lr] * lazy2[rt] % mod ;
        sum3[lr] = ( lazy2[rt] * lazy2[rt] % mod * lazy2[rt] % mod * sum3[lr] % mod
                    + 3 * lazy2[rt] % mod * lazy2[rt] % mod * sum2[lr] % mod * lazy1[rt] % mod +
                    + 3 * lazy2[rt] % mod * sum1[lr] % mod * lazy1[rt] % mod * lazy1[rt] % mod
                    + ( mid - l + 1 ) * lazy1[rt] % mod * lazy1[rt] % mod * lazy1[rt] % mod
                    ) % mod ;
        sum2[lr] = ( lazy2[rt] * lazy2[rt] % mod * sum2[lr] % mod
                    + 2 * lazy1[rt] % mod * lazy2[rt] % mod * sum1[lr] % mod
                    + ( mid - l + 1 ) * lazy1[rt] % mod * lazy1[rt] % mod ) % mod ;
        sum1[lr] = ( sum1[lr] * lazy2[rt] % mod + lazy1[rt]*( mid - l + 1 ) % mod ) % mod;

        lazy1[rr] = ( lazy1[rr] * lazy2[rt] % mod + lazy1[rt] ) % mod ;
        lazy2[rr] = lazy2[rr] * lazy2[rt] % mod ;
        sum3[rr] = ( lazy2[rt] * lazy2[rt] % mod * lazy2[rt] % mod * sum3[rr] % mod
                    + 3 * lazy2[rt] % mod * lazy2[rt] % mod * sum2[rr] % mod * lazy1[rt] % mod +
                    + 3 * lazy2[rt] % mod * sum1[rr] % mod * lazy1[rt] % mod * lazy1[rt] % mod
                    + ( r - mid  ) * lazy1[rt] % mod * lazy1[rt] % mod * lazy1[rt] % mod
                    ) % mod ;
        sum2[rr] = ( lazy2[rt] * lazy2[rt] % mod * sum2[rr] % mod
                    + 2 * lazy1[rt] % mod * lazy2[rt] % mod * sum1[rr] % mod
                    + ( r - mid ) * lazy1[rt] % mod * lazy1[rt] % mod ) % mod ;
        sum1[rr] = ( sum1[rr] * lazy2[rt] % mod + lazy1[rt]*( r - mid ) % mod ) % mod;
        lazy1[rt] = 0;  lazy2[rt] = 1;
        }
}

void update( int l , int r , int rt , int L , int R , int c , int op ) {
    if( l == L && r == R ) {                // suppose lazy1 = lazy2 = 0 ; op1
        c %= mod ;
        if( op == 1 ) {
            lazy1[rt] = ( c + lazy1[rt] ) % mod;
            sum3[rt] = ( sum3[rt]
                       + 3 * sum2[rt] % mod * c % mod
                       + 3 * sum1[rt] % mod * c % mod * c % mod
                       + c * c % mod * c % mod * ( r - l + 1 ) % mod
                       ) % mod;
            sum2[rt] = ( sum2[rt]
                        + 2 * sum1[rt] % mod * c % mod
                        + c * c % mod * ( r - l + 1 ) % mod
                        ) % mod ;
            sum1[rt] = ( sum1[rt] + ( r - l + 1 ) * c % mod ) % mod;
        }
        else if( op == 2 ) {
            lazy1[rt] = lazy1[rt] * c % mod ;
            lazy2[rt] = lazy2[rt] * c % mod ;
            sum1[rt] = sum1[rt] * c % mod ;
            sum2[rt] = sum2[rt] * c % mod * c % mod ;
            sum3[rt] = sum3[rt] * c % mod * c % mod * c % mod ;
        }
        else {
            lazy1[rt] = 0  ; lazy2[rt] = 1 ; lazy3[rt] = c % mod ;
            sum1[rt] = (r-l+1) * c % mod ;
            sum2[rt] = (r-l+1) * c % mod * c % mod;
            sum3[rt] = (r-l+1) * c % mod * c % mod *c % mod;
        }
        return ;
    }
    Down(l,r,rt);
    int mid = (l+r)>>1;
    if( R <= mid ) update(lson,L,R,c,op);
    else if( L > mid ) update(rson,L,R,c,op);
    else update(lson,L,mid,c,op),update(rson,mid+1,R,c,op);
    Up(rt);
}

int query( int l , int r , int rt , int L , int R , int c ) {
    if( l == L && r == R ) {
        if( c == 1 ) return sum1[rt] ;
        else if( c == 2 ) return sum2[rt];
        else return sum3[rt];
    }
    Down(l,r,rt);
    int mid = (l+r)>>1;
    if( R <= mid ) return query(lson,L,R,c);
    else if( L > mid ) return query(rson,L,R,c);
    else return (query(lson,L,mid,c)+query(rson,mid+1,R,c))%mod;
}

int main()
{
    #ifdef LOCAL
       freopen("in.txt","r",stdin);
       //freopen("out.txt","w",stdout);
    #endif // LOCAL
    while( ~scanf("%d%d",&n,&m ) ) {
        if( n == 0 && m == 0 ) break ;
        build( root ) ;
        int op , x , y , c ;
        while( m-- ) {
            scanf("%d%d%d%d",&op,&x,&y,&c);
            if( op != 4 ) update(root,x,y,c,op);
            else printf("%d\n",query(root,x,y,c));
        }
    }
}

时间: 2024-10-06 00:47:40

hdu 4578 Transformation(线段树)的相关文章

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

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 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

HDU 1828 Picture 线段树+扫描线

题意:给你一些矩形的左上角点的坐标和右下角点的坐标,求周长并 最显而易见的思路就是对于x轴和y轴做两次扫描线,对于负数的坐标进行离散化.每次增加的值是线段变化量的绝对值.具体写法和求面积并的差不多. #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt << 1 , l , m

HDU 1542 Atlantis(线段树扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6788    Accepted Submission(s): 2970 Problem Description There are several ancient Greek

POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的,这样理论上是对的 要注意处理高度相同的线段,把底边优先处理(在代码里就是f标记为1的线段),因为若是一个矩形的底边和另一个矩形的上边重合,则这个轮廓肯定不能算 不过POJ和HDU的数据好像都比较弱,我没进行上面的细节处理也AC了,不过一个很简单的数据就会不对,所以还是要处理一下才是真正正确的代码 我

hdu 1542 Atlantis(线段树&amp;扫描线&amp;面积并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6386    Accepted Submission(s): 2814 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

hdu 1828 Picture(线段树&amp;扫描线&amp;周长并)

Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2578    Accepted Submission(s): 1363 Problem Description A number of rectangular posters, photographs and other pictures of the same shap

hdu 1542 Atlantis(线段树)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6899    Accepted Submission(s): 3022 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i