zoukankan      html  css  js  c++  java
  • 30-Transformation(HDU4578)-区间线段树(复杂)

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

                Transformation

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


    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
     
    Source
     

    思路:看题意可以很明显地看出是一道线段树题,也是一道很典型的线段树

    题意相当明显,就不多说了,有三种操作,这三种操作顺序不一样的话得到的结果是不一样的,对于这种多操作的问题,我们要做的事尽量将多种操作合并成一种操作。

    我们可将区间中的数看成是 ax+b的形式,对于加c操作,则变成 ax+b+c(b->b+c),对于乘c操作,则变成 acx+bc,(a->ac,b->bc)对于赋值c操作,则变成c,即(a->1,x->c,b->0),则我们可以在线段数中加以下标记,a,b,x分别是以上提到的变量,sum[3],表示答案,sum[0],sum[1],sum[2]分别表示1次方和,平方和,立方和。对于更新和查询操作我们用pushdown函数向下更新。对于维护平方和还有立方和的问题,我们只要将平方,立方展开再利用更新之前的值即可维护,具体方法这里不多说了

    需要说明的是:每次取修改值,如果发现当前遍历区间完全在需要更新的区间内时,更新当前顶点,同时记录本次以及以前的修改操作,此时不再往后跟新。

    后面pushdown时就是从这个节点读取修改信息更新后面的点。

    关键代码处给出了推到公式:

    #include <iostream>
    #include <string.h>
    #include <stdio.h>
    #include <algorithm>
    #define maxn 100010
    #define mod 10007
    #define mid ((t[p].l+t[p].r)>>1)
    #define ls (p<<1)
    #define rs (ls|1)
    using namespace std;
    struct tree
    {
        int l,r;
        int a,b,c;  //a * x + b: a为乘法系数, b为需要加的值 ; c 放重置的值 
        int sum[3]; //三个次方的求和 
    }t[maxn<<2];
    void pushup(int p)
    {
        int i;
        for(i=0;i<3;i++)
        t[p].sum[i]=(t[ls].sum[i]+t[rs].sum[i])%mod;
    }
    void pushdown(int p)
    {
        if(t[p].l==t[p].r)
        return;
         int a=t[p].a,b=t[p].b,c=t[p].c;
         if(c) //需要重置 
         {
             t[ls].a=t[rs].a=a;
             t[ls].b=t[rs].b=b;
             t[ls].c=t[rs].c=c;
             //sum2 = k * (a * c + b)^2 //重置后每个数相同 
             t[ls].sum[2]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
             t[ls].sum[1]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
             t[ls].sum[0]=(t[ls].r-t[ls].l+1)*(a*c%mod+b)%mod;
             t[rs].sum[2]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
             t[rs].sum[1]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod*(a*c%mod+b)%mod;
             t[rs].sum[0]=(t[rs].r-t[rs].l+1)*(a*c%mod+b)%mod;
         }
         else //未重置,向下更新求和 
         {
             t[ls].a=(t[ls].a*a)%mod;
             t[ls].b=(t[ls].b*a+b)%mod; //先算乘法,再算加法,即:b = b * a + b'; 
             t[rs].a=(t[rs].a*a)%mod;
             t[rs].b=(t[rs].b*a+b)%mod;
             //(av + b)^3 = a^3*v^3 + b^3 + 3a^2 * v^2 * b + 3av * b^2  //k为区间长度 
    		 //		求和为=	a^3*sum2 + K * b^3 + 3a^2 * b * sum1 + 3a*b^2 * sum0 								 
             t[ls].sum[2]=(a*a%mod*a%mod*t[ls].sum[2]%mod+3*a%mod*a%mod*b%mod*t[ls].sum[1]%mod+3*a%mod*b%mod*b%mod*t[ls].sum[0]%mod+b*b%mod*b%mod*(t[ls].r-t[ls].l+1)%mod)%mod;
             //(av + b)^2=a^2*v^2 + b^2 + 2*a*b*v 求和:a^2*sum1 + b^2*k + 2ab*sum1  
    		 t[ls].sum[1]=(a*a%mod*t[ls].sum[1]%mod+b*b%mod*(t[ls].r-t[ls].l+1)%mod+2*a*b%mod*t[ls].sum[0]%mod)%mod;
    		 //av + b 求和:a*sum0 + b*k 
    		 t[ls].sum[0]=(a*t[ls].sum[0]%mod+b*(t[ls].r-t[ls].l+1)%mod)%mod;
    		 
             t[rs].sum[2]=(a*a%mod*a%mod*t[rs].sum[2]%mod+3*a%mod*a%mod*b%mod*t[rs].sum[1]%mod+3*a%mod*b%mod*b%mod*t[rs].sum[0]%mod+b*b%mod*b%mod*(t[rs].r-t[rs].l+1)%mod)%mod;
             t[rs].sum[1]=(a*a%mod*t[rs].sum[1]%mod+b*b%mod*(t[rs].r-t[rs].l+1)%mod+2*a*b%mod*t[rs].sum[0]%mod)%mod;
             t[rs].sum[0]=(a*t[rs].sum[0]%mod+b*(t[rs].r-t[rs].l+1)%mod)%mod;
         }
         t[p].b=t[p].c=0;
         t[p].a=1;
    }
    void build(int p,int l,int r)
    {
        t[p].l=l,t[p].r=r;
        t[p].a=1,t[p].b=t[p].c=0;
        t[p].sum[0]=t[p].sum[1]=t[p].sum[2]=0; //全部初始化为0 
        if(l<r)
        {
            build(ls,l,mid);
            build(rs,mid+1,r);
        }
    }
    void change(int p,int l,int r,int val,int flag)
    {
        if(t[p].l==l&&t[p].r==r)
        {
            if(flag==0)//加val 
            {
                t[p].b=(t[p].b+val)%mod;
                //y = (x + v)^3 //x为原来的值
    			//y = x^3 + v^3 + 3 * x^2 * v + 3 * x * v^2;求和 = sum2 + v^3 + 3*sum1*v + 3*sum0*v^2
                t[p].sum[2]=(t[p].sum[2]+3*val%mod*t[p].sum[1]%mod+3*val%mod*val%mod*t[p].sum[0]%mod+val*val%mod*val%mod*(t[p].r-t[p].l+1)%mod)%mod;
                t[p].sum[1]=(t[p].sum[1]+val*val%mod*(t[p].r-t[p].l+1)%mod+2*val*t[p].sum[0]%mod)%mod;
                t[p].sum[0]=(t[p].sum[0]+val*(t[p].r-t[p].l+1))%mod;
            }
            else if(flag==1) //乘以val 
            {
                t[p].a=(t[p].a*val)%mod;
                t[p].b=(t[p].b*val)%mod;
                //y = (x * v)^3 = x^3 * v^3;求和 = v^3 * sum2 
                t[p].sum[2]=val*val%mod*val%mod*t[p].sum[2]%mod;
                t[p].sum[1]=val*val%mod*t[p].sum[1]%mod;
                t[p].sum[0]=val*t[p].sum[0]%mod;
            }
            else if(flag==2) //重置为val 
            {
                t[p].a=1;
                t[p].b=0;
                t[p].c=val;
    			//y = (v)^3   
                t[p].sum[2]=(t[p].r-t[p].l+1)%mod*val%mod*val%mod*val%mod;
                t[p].sum[1]=(t[p].r-t[p].l+1)%mod*val%mod*val%mod;
                t[p].sum[0]=(t[p].r-t[p].l+1)*val%mod;
            }
            return;
        }
        pushdown(p);
        if(l>mid)
        change(rs,l,r,val,flag);
        else if(r<=mid)
        change(ls,l,r,val,flag);
        else
        {
            change(ls,l,mid,val,flag);
            change(rs,mid+1,r,val,flag);
        }
        pushup(p);
    }
    int query(int p,int l,int r,int flag)
    {
        if(t[p].l==l&&t[p].r==r)
        return t[p].sum[flag];
        pushdown(p);
        if(l>mid)
        return query(rs,l,r,flag);
        else if(r<=mid)
        return query(ls,l,r,flag);
        else
        {
            return (query(ls,l,mid,flag)+query(rs,mid+1,r,flag))%mod;
        }
    }
    int main()
    {
    //    freopen("dd.txt","r",stdin);
        int n,m;
        while(scanf("%d%d",&n,&m)&&(n+m))
        {
            build(1,1,n);
            int q,x,y,c;
            while(m--)
            {
                scanf("%d%d%d%d",&q,&x,&y,&c);
                if(q==4)
                {
                    printf("%d
    ",query(1,x,y,c-1));
                }
                else
                {
                    change(1,x,y,c,q-1);
                }
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    jquery ajax loading效果
    php中count 多维数组长度统计实现方法
    jquery 中Map、each的应用
    转:php获取网页内容方法总结
    经典JavaScript正则表达式实战
    JQuery this 和 $(this) 的区别
    Windows Server 2003 的 Boot.ini 文件的/3GB开关选项
    用ghost装双系统(装03,xp系统)
    Possible memory leak with ReportViewer.RefreshReport() ReportViewer内存回收缺陷
    添加IIS出错,提示缺少CONVLOG.exe文件
  • 原文地址:https://www.cnblogs.com/zhumengdexiaobai/p/9543649.html
Copyright © 2011-2022 走看看