Transformation HDU-4578(线段树)

题目链接: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): 10436 Accepted Submission(s): 2697

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

在做这道题之前大家先去做一下洛谷上的一道相似的题,但是比这道题简单一点,附上题目链接:
https://www.luogu.org/problem/P2023。

这道题真的是神仙题,在培训期间做的,打排位赛的时候想在练习一下线段树,所以在kuangbin上找了这道题来做,然后心态崩了,当时没做出来,就继续打排位赛了,打完了之后有一天没看了,然后今天来补这道题,从早上一直WA到晚上,才AC,博主都快疯了,找到了一点bug就去交,然后就WA,知道最后才发现公式整错了。。。好了,发完了牢骚,现在讲一下这道题吧。
这是一道线段树的好题。
题意大意是:
对于一个长度为N的序列a支持以下操作:
1:令所有满足l<=i<=r的ai全部编程ai+c。
2:令所有满足l<=i<=r的ai全部变为ai*c。
3:令所有满足l<=i<=r的ai全部变为c。
4:查询所有满足l<=i<=r的ai的p次方的和,并输出。
对于这道题来说,P的取值为1<=p<=3,所以可以用三个值来记录所区间中数的p次方的值,然后如果是进行乘法,就乘以给出的数的相对应的次方,如果是加法就应用乘法分配律将一个数的变化装换为区间中的数的变换。
比如说:
如果我们更新加法之后的区间的值,那么对于一个结点的更新公式为:

平方:datep=(date+c)*(date+c)=date*date+2*date*c+c*c=datep+2*date*c+c*c.
立方:datel=(date+c)*(date+c)*(date+c)=date^3+3*date*c^2+3*date^2*c+c^3.

然后通过一个结点的更新推到区间的更新,通过乘法分配律,

datepq(区间总值)=(datep1+2*date1*c+c*c)+(datep2+2*date2*c+c*c)+(datep3+2*date3*c+c*c)+...+(datepr+2*dater*c+c*c)=datepq+2*dateq*c+len*c*c.

3次幂的时候也是一样的推理,然后我们就可以直接通过懒标记计算了(博主就是在这里WA了半天,枯了)。
然后就是处理优先级的问题了,加法和乘法的运算顺序,如果在乘法运算之前有加法,那么也需要把加法的懒标记也加入乘法的运算,这个也是乘法分配律的内容。如果遇到赋值的要求就将之前的标记全部初始化,因为有了赋值操作之后,之前的运算都算全部作废了,然后更新结点的值就Ok了,说了这么多,接下来就直接看代码吧。我觉得其实看代码更容易看懂吧。
代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int mod=10007;
typedef long long ll;
const int maxn=1e5+7;
struct node
{
    ll l,r;
    ll lazyc,lazyj,date;
    ll lazyd;
    ll date1,date2;
}t[maxn<<2];

void build(ll root,ll l,ll r)
{
    t[root].l=l;
    t[root].r=r;
    t[root].date=0;
    t[root].date1=0;
    t[root].date2=0;
    t[root].lazyc=1;
    t[root].lazyd=0;
    t[root].lazyj=0;
    if(l==r)return ;
    ll mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
}

ll quite_mi(ll n,ll m);

void pushdown(ll root)
{
    if(t[root].lazyd){
        t[root<<1].date=(t[root<<1].r-t[root<<1].l+1)%mod*(t[root].lazyd%mod)%mod;
        t[root<<1|1].date=(t[root<<1|1].r-t[root<<1|1].l+1)%mod*(t[root].lazyd%mod)%mod;

        t[root<<1].date1=(t[root<<1].r-t[root<<1].l+1)%mod*(quite_mi(t[root].lazyd,2)%mod)%mod;
        t[root<<1|1].date1=(t[root<<1|1].r-t[root<<1|1].l+1)%mod*(quite_mi(t[root].lazyd,2)%mod)%mod;

        t[root<<1].date2=(t[root<<1].r-t[root<<1].l+1)%mod*(quite_mi(t[root].lazyd,3)%mod)%mod;
        t[root<<1|1].date2=(t[root<<1|1].r-t[root<<1|1].l+1)%mod*(quite_mi(t[root].lazyd,3)%mod)%mod;

        t[root<<1].lazyc=1;
        t[root<<1|1].lazyc=1;

        t[root<<1].lazyj=0;
        t[root<<1|1].lazyj=0;

        t[root<<1].lazyd=t[root].lazyd;
        t[root<<1|1].lazyd=t[root].lazyd;

        t[root].lazyd=0;
    }
    if(t[root].lazyc>1){
        t[root<<1].date=(t[root<<1].date%mod*(t[root].lazyc%mod))%mod;
        t[root<<1|1].date=(t[root<<1|1].date%mod*(t[root].lazyc%mod))%mod;

        //平方
        t[root<<1].date1=(t[root<<1].date1*(quite_mi(t[root].lazyc,2)%mod))%mod;
        t[root<<1|1].date1=(t[root<<1|1].date1*(quite_mi(t[root].lazyc,2)%mod))%mod;

        //立方
        t[root<<1].date2=(t[root<<1].date2*(quite_mi(t[root].lazyc,3)%mod))%mod;
        t[root<<1|1].date2=(t[root<<1|1].date2*(quite_mi(t[root].lazyc,3)%mod))%mod;

        //状态转移
        t[root<<1].lazyc=(t[root<<1].lazyc%mod*(t[root].lazyc%mod))%mod;
        t[root<<1|1].lazyc=(t[root<<1|1].lazyc%mod*(t[root].lazyc%mod))%mod;

        t[root<<1].lazyj=(t[root<<1].lazyj%mod*(t[root].lazyc%mod))%mod;
        t[root<<1|1].lazyj=(t[root<<1|1].lazyj%mod*(t[root].lazyc%mod))%mod;

        t[root].lazyc=1;
    }
    if(t[root].lazyj){
        int lenl=t[root<<1].r-t[root<<1].l+1;
        int lenr=t[root<<1|1].r-t[root<<1|1].l+1;
        lenl%=mod;
        lenr%=mod;

        //立方和公式第一步
        t[root<<1].date2=(t[root<<1].date2+3*(t[root].lazyj%mod)%mod*(t[root<<1].date1%mod))%mod;
        t[root<<1|1].date2=(t[root<<1|1].date2+3*(t[root].lazyj%mod)%mod*(t[root<<1|1].date1%mod))%mod;

        //立方和公式第二步
        t[root<<1].date2=(t[root<<1].date2+3*(t[root<<1].date)%mod*(quite_mi(t[root].lazyj,2)%mod))%mod;
        t[root<<1|1].date2=(t[root<<1|1].date2+3*(t[root<<1|1].date)%mod*(quite_mi(t[root].lazyj,2)%mod))%mod;

        //立方和第三步
        t[root<<1].date2=(t[root<<1].date2+lenl*quite_mi(t[root].lazyj,3)%mod)%mod;
        t[root<<1|1].date2=(t[root<<1|1].date2+lenr*quite_mi(t[root].lazyj,3)%mod)%mod;

        //平方和公式
        t[root<<1].date1=(t[root<<1].date1+2*t[root<<1].date%mod*(t[root].lazyj%mod)%mod)%mod;
        t[root<<1|1].date1=(t[root<<1|1].date1+2*t[root<<1|1].date%mod*(t[root].lazyj%mod)%mod)%mod;

        //平方和公式第二步
        t[root<<1].date1=(t[root<<1].date1+lenl*quite_mi(t[root].lazyj,2)%mod)%mod;
        t[root<<1|1].date1=(t[root<<1|1].date1+lenr*quite_mi(t[root].lazyj,2)%mod)%mod;

        //一次
        t[root<<1].date=(t[root<<1].date%mod+lenl*t[root].lazyj%mod)%mod;
        t[root<<1|1].date=(t[root<<1|1].date%mod+lenr*t[root].lazyj%mod)%mod;

        t[root<<1].lazyj=(t[root<<1].lazyj%mod+(t[root].lazyj%mod))%mod;
        t[root<<1|1].lazyj=(t[root<<1|1].lazyj%mod+(t[root].lazyj%mod))%mod;

        t[root].lazyj=0;
    }
}

void change(ll root,ll l,ll r,ll c,int flag)
{
    if(l<=t[root].l && r>=t[root].r){
        if(flag==3){
            t[root].date=(t[root].r-t[root].l+1)%mod*(c%mod)%mod;
            t[root].date1=(t[root].r-t[root].l+1)%mod*quite_mi(c,2)%mod;
            t[root].date2=(t[root].r-t[root].l+1)%mod*quite_mi(c,3)%mod;
            t[root].date%=mod;
            t[root].date1%=mod;
            t[root].date2%=mod;
            t[root].lazyd=c;
            t[root].lazyc=1;
            t[root].lazyj=0;
            return ;
        }
        int len=t[root].r-t[root].l+1;
        len%=mod;
        if(flag==2){
            t[root].date=(t[root].date%mod*(c%mod))%mod;

            //平方
            t[root].date1=(t[root].date1%mod*(quite_mi(c,2)%mod))%mod;

            //立方
            t[root].date2=(t[root].date2%mod*(quite_mi(c,3)%mod))%mod;

            t[root].lazyc=(t[root].lazyc%mod*(c%mod))%mod;
            t[root].lazyj=(t[root].lazyj%mod*(c%mod))%mod;
            return ;
        }
        if(flag==1){//加法
            //立方
            t[root].date2=(t[root].date2+3*(c%mod)%mod*(t[root].date1%mod)%mod+3*(t[root].date%mod)*(quite_mi(c%mod,2)%mod)%mod+len*quite_mi(c,3)%mod)%mod;

            //平方
            t[root].date1=(t[root].date1+2*(c%mod)%mod*t[root].date%mod+len*quite_mi(c%mod,2)%mod)%mod;

            t[root].date=(t[root].date+(t[root].r-t[root].l+1)%mod*(c%mod))%mod;
            t[root].lazyj=(t[root].lazyj+c%mod)%mod;
            return ;
        }
    }
    pushdown(root);
    ll mid=(t[root].l+t[root].r)>>1;
    if(l<=mid){
        change(root<<1,l,r,c,flag);
    }
    if(r>mid){
        change(root<<1|1,l,r,c,flag);
    }
    t[root].date=(t[root<<1].date+t[root<<1|1].date)%mod;
    t[root].date1=(t[root<<1].date1+t[root<<1|1].date1)%mod;
    t[root].date2=(t[root<<1].date2+t[root<<1|1].date2)%mod;
}

ll quite_mi(ll n,ll m)
{
    ll ans=1;
    while(m){
        if(m&1) ans=(ans%mod*(n%mod))%mod;
        n=((n%mod)*(n%mod))%mod;
        m>>=1;
    }
    return ans;
}

ll query(ll root,ll l,ll r,ll p)
{
    if(r<t[root].l || t[root].r<l)return 0;
    if(l<=t[root].l && r>=t[root].r){
        if(p==1){
            return t[root].date%mod;
        }
        else if(p==2){
            return t[root].date1%mod;
        }
        else{
            return t[root].date2%mod;
        }
    }
    ll mid=(t[root].l+t[root].r)>>1;
    pushdown(root);
    ll ans=0;
    if(l<=mid){
        ans=(ans+query(root<<1,l,r,p))%mod;
    }
    if(r>mid){
        ans=(ans+query(root<<1|1,l,r,p))%mod;
    }
    return ans;
}

int main()
{
    ll n,m;
    while(~scanf("%lld%lld",&n,&m)){
        if(n==0 || m==0){
            return 0;
        }
        build(1,1,n);
        while(m--){
            int flag;
            ll l,r,p;
            scanf("%d%lld%lld%lld",&flag,&l,&r,&p);
            if(flag==4){
                printf("%lld\n",query(1,l,r,p)%mod);
            }
            else{
                //p%=mod;
                change(1,l,r,p,flag);
            }
        }
    }
    return 0;
}
发布了34 篇原创文章 · 获赞 3 · 访问量 259

猜你喜欢

转载自blog.csdn.net/qq_44641782/article/details/101710829