• [线段树] (g) hdu4578 线段树维护区间幂次和(好题)


    题目: hdu4578 Transformation

    大意: 长度为n的序列初始全为0,m个操作,有多组数据

        操作有:1. 区间加k   

              2. 区间乘k

              3. 区间内全改为k 

              4. 求区间内每个数的k次幂和(1<=k<=3)


    解析:

    1. 区间乘自行跳转luogu3373,tag最好先乘后加(分别是操作1、2)
    2. 第三个tag维护操作3,可以发现,一旦被区间推平(指成为同一个数的重复),那么已存的 加乘tag 都没有意义了 ,所以新建第三个tag,维护操作3,优先级 大于乘法大于加法 , 且pushdown时消除其它标记 .
    3. 对于询问4,十分少见,使得我看到这题时直接想到用珂朵莉树来做...但其实只需要用val[][4]即可维护而不用暴力求和,val[root][p]表示节点root下的p次幂和,推导过程如下:...

        01=02=03=0

       若该节点维护的权值为: val[1]=a1+a2+....+an,在操作1中加的数为k

        val[1](new)=val[1]+(r-l+1)*k //详见加法tag

        有(a+b)2=a2+b2+2bk

        原val[2]=[ a12 + a22 +...+ an2]

        有val[2](new)=[ (a1+k)2 + (a2+k)2 +...+ (an+k)2]

            =( a12+a22+...+an2  ) + 2k(a1+a2+....+an) + n*k2

           =val[2]  + (r-l+1)*k+ 2k*val[1](原,此处可看出2的优先级高于1)

        同理

      ∵(a+b)3=a3+b3+3a2b+3ab2
      ∴val[3]=val[3] + 3k∗val[2]+3k2∗val[1] + (r−l+1)∗k3
      显然3的优先级又高于2  


      总结:

        3>2>1(不管是操作的tag还是val...qwq好巧啊)


     注意细节:

      1. 多组数据,因为不能覆盖上一组,所以需要清空(build)

      2. 操作注意优先级

      3. 处处取模避免爆int

      4. 操作复杂,代码量大,不要敲错,很难查错

      5. 尤其注意pushdown部分的检查

      6. 线段树4倍空间

      7. 一起%scPointer

    Code

    /*hdu 4578  by lsy263*/
    
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cctype>
    #include<ctime>
    using namespace std;const int N=1e6+3,scPointer=10007,INF=0x7fffffff;
    int v[N<<2][4],pt[N<<2],mt[N<<2],Assign[N<<2],n,m; //For segment-tree
    #define LS (rt<<1)
    #define RS (LS|1)
    #define pushup(rt)
        (v[rt][1]=v[LS][1]+v[RS][1])%=scPointer;
        (v[rt][2]=v[LS][2]+v[RS][2])%=scPointer;
        (v[rt][3]=v[LS][3]+v[RS][3])%=scPointer;
    inline int squ(int a,int b){   //没有必要快速幂..但是写个函数便于阅读
        int base =a;
        while(--b)(base*=a)%=scPointer;
        int base=1;
        return base;
    }
    void build(int rt,int l,int r){
        pt[rt]=0;mt[rt]=1;Assign[rt]=-INF;
        v[rt][1]=v[rt][2]=v[rt][3]=0;
        if(l==r)return;
        int mid=l+r>>1;
        build(LS,l,mid);
        build(RS,mid+1,r);
        return ;
    }
    inline void pushdown(int rt,int l,int r){
        int mid=l+r>>1;
        if(Assign[rt]!=-INF){ //会覆盖下面所有标记(3pts)
            Assign[LS]=Assign[RS]=Assign[rt];
            ////// -------------   v
            v[LS][1]=(mid-l+1)*Assign[rt]%scPointer;
            v[RS][1]=(r-mid)*Assign[rt]%scPointer;
            v[LS][2]=(mid-l+1)*squ(Assign[rt],2)%scPointer;
            v[RS][2]=(r-mid)*squ(Assign[rt],2)%scPointer;
            v[LS][3]=(mid-l+1)*squ(Assign[rt],3)%scPointer;
            v[RS][3]=(r-mid)*squ(Assign[rt],3)%scPointer;
            ///// --------------
            mt[LS]=1,pt[LS]=0;
            mt[RS]=1,pt[RS]=0;
            Assign[rt]=-INF;
            //return;
        }
        if(mt[rt]!=1){
            ///// --------------   Tag
            (pt[LS]*=mt[rt])%=scPointer;    
            (pt[RS]*=mt[rt])%=scPointer;
            (mt[LS]*=mt[rt])%=scPointer;    
            (mt[RS]*=mt[rt])%=scPointer;
            ///// --------------   v
            (v[LS][1]*=mt[rt])%=scPointer;
            (v[RS][1]*=mt[rt])%=scPointer;
            (v[LS][2]*=squ(mt[rt],2))%=scPointer;
            (v[RS][2]*=squ(mt[rt],2))%=scPointer;
            (v[LS][3]*=squ(mt[rt],3))%=scPointer;
            (v[RS][3]*=squ(mt[rt],3))%=scPointer;
            ///// --------------
            mt[rt]=1;
        }
        if(pt[rt]){
            ///// --------------   Tag
            (pt[LS]+=pt[rt])%=scPointer;    
            (pt[RS]+=pt[rt])%=scPointer;
            ///// --------------   v
            (v[LS][3]+=3*v[LS][2]*pt[rt]%scPointer+3*squ(pt[rt],2)*v[LS][1]%scPointer+(mid-l+1)*squ(pt[rt],3)%scPointer)%=scPointer;
            (v[RS][3]+=3*v[RS][2]*pt[rt]%scPointer+3*squ(pt[rt],2)*v[RS][1]%scPointer+(r-mid)*squ(pt[rt],3)%scPointer)%=scPointer;
            (v[LS][2]+=2*pt[rt]*v[LS][1]%scPointer+(mid-l+1)*squ(pt[rt],2)%scPointer)%=scPointer;
            (v[RS][2]+=2*pt[rt]*v[RS][1]%scPointer+(r-mid)*squ(pt[rt],2)%scPointer)%=scPointer;
            (v[LS][1]+=(mid-l+1)*pt[rt])%=scPointer;    
            (v[RS][1]+=(r-mid)*pt[rt])%=scPointer;
            ///// --------------
            /*
            v[3]+=3kv[2]+3v[1]k^2+len*k^3
            v[2]+=2kv[1]+len*k^2
            v[1]+=len*k
            */
            pt[rt]=0;
        }return;
    }
    inline void update(int rt,int l,int r,int x,int y,int k,int ty){  //Update 
        if(l>=x&&r<=y){ //推平要清空tag
            switch(ty){
                case 1: //Plus
                    (pt[rt]+=k)%=scPointer;
                    (v[rt][3]+=3*v[rt][2]*k%scPointer+3*squ(k,2)*v[rt][1]%scPointer+(r-l+1)*squ(k,3))%=scPointer;
                    (v[rt][2]+=2*k*v[rt][1]+(r-l+1)*squ(k,2))%=scPointer;
                    (v[rt][1]+=(r-l+1)*k)%=scPointer;
                    /*
                    v[3]+=3kv[2]+3v[1]k^2+len*k^3
                    v[2]+=2kv[1]+len*k^2
                    v[1]+=len*k
                    */
                    break;
                case 2: //Mul
                    (pt[rt]*=k)%=scPointer;
                    (mt[rt]*=k)%=scPointer;
                    (v[rt][1]*=k)%=scPointer;
                    (v[rt][2]*=squ(k,2))%=scPointer;
                    (v[rt][3]*=squ(k,3))%=scPointer;
                    break;
                default: //Assign
                    Assign[rt]=k;mt[rt]=1;pt[rt]=0;
                    v[rt][1]=(r-l+1)*k%scPointer;
                    v[rt][2]=(r-l+1)*squ(k,2)%scPointer;
                    v[rt][3]=(r-l+1)*squ(k,3)%scPointer;
            } return;
        }pushdown(rt,l,r);
        int mid=l+r>>1;
        if(x<=mid)update(LS,l,mid,x,y,k,ty);
        if(y>mid)update(RS,mid+1,r,x,y,k,ty);
        pushup(rt); return;
    }
    int query(int rt,int l,int r,int x,int y,int p){
        if(l>=x&&r<=y)
            return v[rt][p]%scPointer;
        pushdown(rt,l,r);
        int mid=l+r>>1,res=0;
        if(x<=mid)(res+=query(LS,l,mid,x,y,p))%=scPointer;
        if(y>mid)(res+=query(RS,mid+1,r,x,y,p))%=scPointer;
        return res;
    }
    int main(){int tp,x,y,k;
        while(scanf("%d%d",&n,&m)!=EOF&&n&&m){
            build(1,1,n);
            while(m --){
                scanf("%d%d%d%d",&tp,&x,&y,&k);
                if(tp==4)
                    printf("%d
    ",query(1,1,n,x,y,k)%scPointer);
                else 
                    update(1,1,n,x,y,k%scPointer,tp);
            }
        }
        return 0;
    }
  • 相关阅读:
    PHP-redis命令之 列表(lists)
    PHP-redis命令之 散列(hashes)
    PHP-redis命令之 字符串 (strings)
    CentOS 7.0:搭建SVN服务器
    Redis 数据类型分析 字符串 哈希 列表 集合 有序集合 优缺点 分析 注意事项 存储结构
    CentOS 7安装配置Redis数据库
    封装微信分享到朋友/朋友圈js
    PHP 微信分享(及二次分享)
    Ajax登陆,使用Spring Security缓存跳转到登陆前的链接
    IDEA thymeleaf ${xxx.xxx}表达式报错,红色波浪线
  • 原文地址:https://www.cnblogs.com/lsy263/p/11192345.html
Copyright © 2020-2023  润新知