HDU 4578 Transformation 【線段樹】

題目來源:http://acm.hdu.edu.cn/showproblem.php?pid=4578
在這裏插入圖片描述


★這題有有3個操作,需要考慮的因素比較多,


題意:

有n個數,4種操作
①:把[ l , r ]的每個數加上c
②:把[ l , r ]的每個數乘上c
③:把[ l , r ]的每個數變成c
④:輸出[ l , r ]之間的數的 k次方的和 k=1,2,3


思路:

首先要明確的一點,前三種操作都需要用 懶標記(lazy_tag),故需要三個標記(記爲add , mult ,rep)
在詢問的時候,可能是區間和、區間平方和、區間立方和,不妨維護這三個值(記爲 sum1 ,sum2 ,sum3)

然後問題來了,當標記下傳的時候,怎麼處理這三個懶標記的關係呢?

初始化的時候add=0, mult=1, rep=0
當進行了操作三,很明顯add=0 mult=1
進行操作二時,要 add[k]=add[k]*v%mod; 這樣就可以默認每次是 先乘再加的了
然後就是簡單的公式推導了 瘋狂取模
當 (rep[ k ] != 0)時
sum1=∑( tmp )
sum2=∑( tmp )2
sum3=∑( tmp )3
當 (add[ k ] != 0 || mult[ k ] != 1)時
sum1= ∑(ab+c)
sum2= ∑(ab+c) 2
sum3= ∑(ab+c) 3
把他們化簡開就是代碼中那段很長的式子了


代碼

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
using namespace std;
const int maxn=1e5+5;
const int sz=1<<10;
const int mod=1e4+7;
const int inf=2e9;
const double eps=1e-8;
const double pi=acos(-1);
typedef long long LL;
int n,m;
int sum1[maxn<<2],sum2[maxn<<2],sum3[maxn<<2];
int add[maxn<<2],mult[maxn<<2],rep[maxn<<2];
template<class t>
inline void read(t &x)
{
    char c; x=1;
    while((c=getchar())<'0'||c>'9') if(c=='-') x=-1;
    t res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=res*10+c-'0';
    x*=res;
}
void build(int k,int l,int r)
{
    mult[k]=1;
    add[k]=rep[k]=0;
    sum1[k]=sum2[k]=sum3[k]=0;
    if(l==r) return ;
    int mid=l+r>>1;
    build(ls); build(rs);
}
void pushdown(int k,int l,int r,int mid)
{
    if(rep[k]!=0){
        rep[k<<1]=rep[k<<1|1]=rep[k];
        rep[k]=0;
        add[k<<1]=add[k<<1|1]=0;
        mult[k<<1]=mult[k<<1|1]=1;
        int tmp=rep[k<<1];
        sum1[k<<1]=(mid-l+1)*tmp%mod;
        sum2[k<<1]=sum1[k<<1]*tmp%mod;
        sum3[k<<1]=sum2[k<<1]*tmp%mod;
        sum1[k<<1|1]=(r-mid)*tmp%mod;
        sum2[k<<1|1]=sum1[k<<1|1]*tmp%mod;
        sum3[k<<1|1]=sum2[k<<1|1]*tmp%mod;
    }
    if(add[k]!=0||mult[k]!=1){
        add[k<<1]=(add[k<<1]*mult[k]%mod+add[k])%mod;
        add[k<<1|1]=(add[k<<1|1]*mult[k]%mod+add[k])%mod;
        mult[k<<1]=mult[k<<1]*mult[k]%mod;
        mult[k<<1|1]=mult[k<<1|1]*mult[k]%mod;

        int b=mult[k],c=add[k];
        //(a^3*b^3+3*a^2*b^2*c+3*a*b*c^2+c^3)
        //(a^2*b^2+2*a*b*c+c^2)
        sum3[k<<1]=(b*b%mod*b%mod*sum3[k<<1]%mod+3*b%mod*b%mod*c%mod*sum2[k<<1]%mod+3*c%mod*c%mod*b%mod*sum1[k<<1]%mod+(mid-l+1)*c%mod*c%mod*c%mod)%mod;
        sum2[k<<1]=(b*b%mod*sum2[k<<1]%mod+2*b%mod*c%mod*sum1[k<<1]%mod+(mid-l+1)*c%mod*c%mod)%mod;
        sum1[k<<1]=(b*sum1[k<<1]%mod+(mid-l+1)*c%mod)%mod;
        sum3[k<<1|1]=(b*b%mod*b%mod*sum3[k<<1|1]%mod+3*b%mod*b%mod*c%mod*sum2[k<<1|1]%mod+3*c%mod*c%mod*b%mod*sum1[k<<1|1]%mod+(r-mid)*c%mod*c%mod*c%mod)%mod;
        sum2[k<<1|1]=(b*b%mod*sum2[k<<1|1]%mod+2*b%mod*c%mod*sum1[k<<1|1]%mod+(r-mid)*c%mod*c%mod)%mod;
        sum1[k<<1|1]=(b*sum1[k<<1|1]%mod+(r-mid)*c%mod)%mod;

        add[k]=0; mult[k]=1;
    }
}
void update(int k,int l,int r,int x,int y,int v,int type)
{
    if(x<=l&&r<=y){
        v%=mod;
        if(type==1){
            add[k]=(add[k]+v)%mod;
            sum3[k]=(sum3[k]+3*sum2[k]%mod*v%mod+3*sum1[k]%mod*v%mod*v%mod+(r-l+1)*v%mod*v%mod*v%mod)%mod;
            sum2[k]=(sum2[k]+2*sum1[k]%mod*v%mod+(r-l+1)*v%mod*v%mod)%mod;
            sum1[k]=(sum1[k]+v*(r-l+1)%mod)%mod;
        }
        else if(type==2){
            add[k]=add[k]*v%mod;
            mult[k]=mult[k]*v%mod;
            sum1[k]=sum1[k]*v%mod;
            sum2[k]=sum2[k]*v%mod*v%mod;
            sum3[k]=sum3[k]*v%mod*v%mod*v%mod;
        }
        else{
            add[k]=0; mult[k]=1; rep[k]=v;
            sum1[k]=(r-l+1)*v%mod;
            sum2[k]=sum1[k]*v%mod;
            sum3[k]=sum2[k]*v%mod;
        }
        return ;
    }
    int mid=l+r>>1;
    pushdown(k,l,r,mid);
    if(mid>=x) update(ls,x,y,v,type);
    if(mid<y) update(rs,x,y,v,type);
    sum1[k]=(sum1[k<<1]+sum1[k<<1|1])%mod;
    sum2[k]=(sum2[k<<1]+sum2[k<<1|1])%mod;
    sum3[k]=(sum3[k<<1]+sum3[k<<1|1])%mod;
}
int query(int k,int l,int r,int x,int y,int type)
{
    if(x<=l&&r<=y){
        if(type==1) return sum1[k];
        else if(type==2) return sum2[k];
        return sum3[k];
    }
    int mid=l+r>>1;
    pushdown(k,l,r,mid);
    int ans=0;
    if(mid>=x) ans=(ans+query(ls,x,y,type))%mod;
    if(mid<y) ans=(ans+query(rs,x,y,type))%mod;
    return ans;
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0) break;
        build(1,1,n);
        int op,a,b,c;
        while(m--){
            read(op); read(a); read(b); read(c);
            if(op==4) printf("%d\n",query(1,1,n,a,b,c));
            else update(1,1,n,a,b,c,op);
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章