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

题意:

//长度为n的数组 四个操作
//1 x y  c [x,y]区间的数都加c
//2 x y c [x, y] 区间的数都乘以c
//3 x y c [x ,y] 区间的数都变为c
//4 x y p [x ,y] 求区间的数的p次方的和

题解:

这道题坑在有三种询问:set , add , mul。所以lazy标记要有三个,如果三个标记同时出现的处理方法——当更新set操作时,就把add标记和mul标记全部取消;当更新mul操作时,如果当前节点add标记存在,就把add标记改为:add * mul。这样的话就可以在PushDown()操作中先执行set,然后mul,最后add。

  麻烦在有三种询问:和 , 平方和 , 立方和。对于set和mul操作来说,这三种询问都比较好弄。

  对于add操作,和的话就比较好弄,按照正常方法就可以;

  平方和这样来推:(a + c)2 = a2 + c2 + 2ac  , 即sum2[rt] = sum2[rt] + (r - l + 1) * c * c + 2 * sum1[rt] * c;

  立方和这样推:(a + c)3 = a3 + c3 + 3c(a2 + ac) , 即sum3[rt] = sum3[rt] + (r - l + 1) * c * c * c + 3 * c * (sum2[rt] + sum1[rt] * c);

  几个注意点:

  1. add标记取消的时候是置0,mul标记取消的时候是置1;
  2. 在PushDown()中也也要注意取消标记,如set操作中取消add和mul,mul操作中更新add;
  3. 在add操作中要注意sum3 , sum2 , sum1的先后顺序,一定是先sum3 , 然后sum2 , 最后sum1;
  4. int容易爆,还是用LL要保险一点;
  5. 最后就是运算较多,不要漏掉东西。

C++版本一 

/*
*@Author:   STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
#define RI register int
using namespace std;
typedef long long ll;
//typedef __int128 lll;
const int N=100000+10;
const int M=100000+10;
const int MOD=10000+7;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,q,p;
int ans,cnt,flag,temp,sum;
ll tree[N<<2];
ll tree2[N<<2];
ll tree3[N<<2];
ll lazy1[N<<2];
ll lazy2[N<<2];
ll lazy3[N<<2];
char str;
struct node{};
ll POW(ll a,int b){
    if (b==1) return a%MOD;
    if (b==2) return a*a%MOD;
    if (b==3) return a*a%MOD*a%MOD;
    return 1;
}
void pushup(int rt){
    tree[rt]=(tree[rt<<1]+tree[rt<<1|1])%MOD;
    tree2[rt]=(tree2[rt<<1]+tree2[rt<<1|1])%MOD;
    tree3[rt]=(tree3[rt<<1]+tree3[rt<<1|1])%MOD;
}
void pushdown(int l,int r,int rt){
    if(lazy3[rt]){
        int mid=(l+r)>>1;
        int llen=(mid-l+1);
        int rlen=(r-mid);
        tree[rt<<1]=(llen*lazy3[rt])%MOD;
        tree[rt<<1|1]=(rlen*lazy3[rt])%MOD;

        tree2[rt<<1]=(llen*POW(lazy3[rt],2))%MOD;
        tree2[rt<<1|1]=(rlen*POW(lazy3[rt],2))%MOD;

        tree3[rt<<1]=(llen*POW(lazy3[rt],3))%MOD;
        tree3[rt<<1|1]=(rlen*POW(lazy3[rt],3))%MOD;

        lazy3[rt<<1|1]=lazy3[rt<<1]=lazy3[rt];
        lazy3[rt]=0;
        lazy1[rt<<1|1]=lazy1[rt<<1]=1;
        lazy2[rt<<1|1]=lazy2[rt<<1]=0;
    }
    if(lazy1[rt]!=1){
        tree[rt<<1]=(tree[rt<<1]*lazy1[rt])%MOD;
        tree[rt<<1|1]=(tree[rt<<1|1]*lazy1[rt])%MOD;

        tree2[rt<<1]=(tree2[rt<<1]*POW(lazy1[rt],2))%MOD;
        tree2[rt<<1|1]=(tree2[rt<<1|1]*POW(lazy1[rt],2))%MOD;

        tree3[rt<<1]=(tree3[rt<<1]*POW(lazy1[rt],3))%MOD;
        tree3[rt<<1|1]=(tree3[rt<<1|1]*POW(lazy1[rt],3))%MOD;



        lazy2[rt<<1]=(lazy2[rt<<1]*lazy1[rt])%MOD;
        lazy2[rt<<1|1]=(lazy2[rt<<1|1]*lazy1[rt])%MOD;
        lazy1[rt<<1]=(lazy1[rt<<1]*lazy1[rt])%MOD;
        lazy1[rt<<1|1]=(lazy1[rt<<1|1]*lazy1[rt])%MOD;
        lazy1[rt]=1;
    }
    if(lazy2[rt]){
        int mid=(l+r)>>1;
        int llen=(mid-l+1);
        int rlen=(r-mid);
        tree3[rt<<1]=(tree3[rt<<1]+(llen*POW(lazy2[rt],3))%MOD+3*lazy2[rt]*tree2[rt<<1]%MOD+3*POW(lazy2[rt],2)*tree[rt<<1]%MOD)%MOD;
        tree3[rt<<1|1]=(tree3[rt<<1|1]+(rlen*POW(lazy2[rt],3))%MOD+3*lazy2[rt]*tree2[rt<<1|1]%MOD+3*POW(lazy2[rt],2)*tree[rt<<1|1]%MOD)%MOD;

        tree2[rt<<1]=(tree2[rt<<1]+(llen*POW(lazy2[rt],2))%MOD+2*tree[rt<<1]*lazy2[rt]%MOD)%MOD;
        tree2[rt<<1|1]=(tree2[rt<<1|1]+(rlen*POW(lazy2[rt],2))%MOD+2*tree[rt<<1|1]*lazy2[rt]%MOD)%MOD;

        tree[rt<<1]=(tree[rt<<1]+(llen*lazy2[rt])%MOD)%MOD;
        tree[rt<<1|1]=(tree[rt<<1|1]+(rlen*lazy2[rt])%MOD)%MOD;


        lazy2[rt<<1]=(lazy2[rt<<1]+lazy2[rt])%MOD;
        lazy2[rt<<1|1]=(lazy2[rt<<1|1]+lazy2[rt])%MOD;
        lazy2[rt]=0;
    }
}
void build(int l,int r,int rt){
    lazy1[rt]=1;
    lazy2[rt]=0;
    lazy3[rt]=0;
    if(l==r){
        //scanf("%lld",&tree[rt]);
        tree[rt]=0;
        tree2[rt]=0;
        tree3[rt]=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void updata(int l,int r,int rt,int L,int R,ll C,int op){
    if(L<=l&&r<=R){
        int len=r-l+1;
        if(op==1){
            tree[rt]=(tree[rt]*C)%MOD;
            tree2[rt]=(tree2[rt]*POW(C,2))%MOD;
            tree3[rt]=(tree3[rt]*POW(C,3))%MOD;

            lazy2[rt]=(lazy2[rt]*C)%MOD;
            lazy1[rt]=(lazy1[rt]*C)%MOD;
        }else if(op==2){
            tree3[rt]=(tree3[rt]+(len*POW(C,3))%MOD+3*C*tree2[rt]%MOD+3*POW(C,2)*tree[rt]%MOD)%MOD;
            tree2[rt]=(tree2[rt]+(len*POW(C,2))%MOD+2*tree[rt]*C%MOD)%MOD;
            tree[rt]=(tree[rt]+len*C)%MOD;
            lazy2[rt]=(lazy2[rt]+C)%MOD;
        }else{
            tree[rt]=(len*C)%MOD;
            tree2[rt]=(len*POW(C,2))%MOD;
            tree3[rt]=(len*POW(C,3))%MOD;
            lazy1[rt]=1;
            lazy2[rt]=0;
            lazy3[rt]=C;
        }
        return;
    }
    int mid=(l+r)>>1;
    pushdown(l,r,rt);
    if(L<=mid)updata(l,mid,rt<<1,L,R,C,op);
    if(mid<R)updata(mid+1,r,rt<<1|1,L,R,C,op);
    pushup(rt);
}
ll query(int l,int r,int rt,int L,int R,int op){
    if(L<=l&&r<=R){
        if(op==1)return tree[rt];
        if(op==2)return tree2[rt];
        if(op==3)return tree3[rt];
    }
    int mid=(l+r)>>1;
    ll res=0;
    pushdown(l,r,rt);
    if(L<=mid)res=(res+query(l,mid,rt<<1,L,R,op))%MOD;
    if(mid<R)res=(res+query(mid+1,r,rt<<1|1,L,R,op))%MOD;
    return res;
}
void see(int l,int r,int rt){
    if(l==r){
        printf("%lld%c",tree3[rt]," \n"[r==n]);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(l,r,rt);
    see(l,mid,rt<<1);
    see(mid+1,r,rt<<1|1);
}
int main()
{
#ifdef DEBUG
	freopen("input.in", "r", stdin);
	//freopen("output.out", "w", stdout);
#endif
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    //scanf("%d",&t);
    //while(t--){
    while(~scanf("%d%d",&n,&m)&&n+m){
        build(1,n,1);
        int op;
        int l,r;
        ll c;
        for(int i=1;i<=m;i++){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d%lld",&l,&r,&c);
                updata(1,n,1,l,r,c,2);
            }else if(op==2){
                scanf("%d%d%lld",&l,&r,&c);
                updata(1,n,1,l,r,c,1);
            }else if(op==3){
                scanf("%d%d%lld",&l,&r,&c);
                updata(1,n,1,l,r,c,3);
            }else if(op==4){
                scanf("%d%d%d",&l,&r,&p);
                printf("%lld\n",query(1,n,1,l,r,p));
            }
            //see(1,n,1);
        }
    }

    //}

#ifdef DEBUG
	printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
#endif
    //cout << "Hello world!" << endl;
    return 0;
}

C++版本二

题解:

//用线段树维护里面的值都相等的区间 ,那么这个区间的所需答案为(r-l+1)*(tree[v].eq)^q
//对于懒惰操作 mul , eq , add的处理是
//对于每次eq操作可以直接操作tree[v].eq = eq ;tree[v].mul = 1 ; tree[v].add = 0;
//而对于mul ,和add的操作每次push_down(v)的时候保证下面一层的所有懒惰情况都是初始情况
//所以对于mul和add操作时就一直往下push_down知道找到一个可以
 

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=100010;
#define left v<<1
#define right v<<1|1
#define mod 10007
struct node{
    int l,r,value;
    int eq,add,mul;
}tree[maxn<<2];
void build(int l,int r,int v){
    tree[v].l=l;
    tree[v].r=r;
    tree[v].add=0;tree[v].mul=1;tree[v].eq=-1;
    if(l==r){
        tree[v].eq=0;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,left);
    build(mid+1,r,right);
}
void push_down(int v){
    if(tree[v].l==tree[v].r)return;

    if(tree[v].eq!=-1){//=
        tree[left].eq=tree[right].eq=tree[v].eq;
        tree[left].add=tree[right].add=0;
        tree[left].mul=tree[right].mul=1;
        tree[v].eq=-1;
        return;
    }
    if(tree[v].mul!=1){//*
        if(tree[left].eq!=-1)
            tree[left].eq=(tree[left].eq*tree[v].mul)%mod;
        else{
            push_down(left);
            tree[left].mul=(tree[left].mul*tree[v].mul)%mod;
        }
        if(tree[right].eq!=-1)
            tree[right].eq=(tree[right].eq*tree[v].mul)%mod;
        else{
            push_down(right);
            tree[right].mul=(tree[right].mul*tree[v].mul)%mod;
        }
        tree[v].mul=1;
    }
    if(tree[v].add){//+
        if(tree[left].eq!=-1)
            tree[left].eq=(tree[left].eq+tree[v].add)%mod;
        else{
            push_down(left);
            tree[left].add=(tree[left].add+tree[v].add)%mod;
        }
        if(tree[right].eq!=-1)
            tree[right].eq=(tree[right].eq+tree[v].add)%mod;
        else{
            push_down(right);
            tree[right].add=(tree[right].add+tree[v].add)%mod;
        }
        tree[v].add=0;
    }
}
void update(int l,int r,int v,int op,int c){
    if(l<=tree[v].l&&tree[v].r<=r){
        if(op==3){
            tree[v].add=0;tree[v].mul=1;
            tree[v].eq=c;
            return;
        }
        if(tree[v].eq!=-1){
            if(op==1)tree[v].eq=(tree[v].eq+c)%mod;
            else tree[v].eq=(tree[v].eq*c)%mod;
        }else{
            push_down(v);
            if(op==1)tree[v].add=(tree[v].add+c)%mod;
            else tree[v].mul=(tree[v].mul*c)%mod;
        }
        return;
    }
    push_down(v);
    int mid=(tree[v].l+tree[v].r)>>1;
    if(l<=mid)update(l,r,left,op,c);
    if(r>mid)update(l,r,right,op,c);
}
int query(int l,int r,int v,int q){
    if(tree[v].l>=l&&tree[v].r<=r&&tree[v].eq!=-1){
        int ans=1;
        for(int i=1;i<=q;i++)
            ans=(ans*tree[v].eq)%mod;
        return(ans*((tree[v].r-tree[v].l+1)%mod))%mod;
    }
    push_down(v);
    int mid=(tree[v].l+tree[v].r)>>1;
    if(l>mid)
        return query(l,r,right,q);
    else if(r<=mid)
        return query(l,r,left,q);
    else
        return(query(l,mid,left,q)+query(mid+1,r,right,q))%mod;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)&&(n+m)){
        int op,x,y,c;
        build(1,n,1);
        while(m--){
            scanf("%d%d%d%d",&op,&x,&y,&c);
            if(op==4)
                printf("%d\n",(query(x,y,1,c)%mod));
            else
                update(x,y,1,op,c);
        }
    }
return 0;
}

C++版本三

///先乘后加的原则,每次更新区间乘法,加法标记就*乘法标记
  
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
#define debug(x) printf("----Line%s----\n",#x)
#define ls rt<<1
#define rs rt<<1|1
#define mod 10007
using namespace std;

const int N = 1e5+5;

ll add[N<<2],mtag[N<<2];
ll t[N<<2],tt[N<<2],ttt[N<<2];
ll isset[N<<2];

ll Pow(ll a,int b){
    if (b==2) return a*a%mod;
    if (b==3) return a*a%mod*a%mod;
}

void push_up(int rt)
{
    t[rt] = (t[ls] + t[rs])%mod;
    tt[rt] = (tt[ls] + tt[rs])%mod;
    ttt[rt] = (ttt[ls] + ttt[rs])%mod;
}

void push_down(int rt,int len)
{
    if (isset[rt]){
        ll x = isset[rt];
        isset[ls] = isset[rs] = isset[rt];
        isset[rt] = 0;
        mtag[ls] = mtag[rs] = 1;
        add[ls] = add[rs] = 0;
        ttt[ls] = (len-len/2)*Pow(x,3)%mod;
        tt[ls] = (len-len/2)*Pow(x,2)%mod;
        t[ls] = (len-len/2)*x%mod;
        ttt[rs] = (len/2)*Pow(x,3)%mod;
        tt[rs] = (len/2)*Pow(x,2)%mod;
        t[rs] = (len/2)*x%mod;
    }
    if (mtag[rt]==1 && add[rt]==0) return ;
    ttt[ls] = (ttt[ls]*Pow(mtag[rt],3)%mod + (len-len/2)*Pow(add[rt],3)%mod + 3*tt[ls]*Pow(mtag[rt],2)%mod*add[rt]%mod + 3*t[ls]*mtag[rt]%mod*Pow(add[rt],2)%mod)%mod;
    ttt[rs] = (ttt[rs]*Pow(mtag[rt],3)%mod +  len/2     *Pow(add[rt],3)%mod + 3*tt[rs]*Pow(mtag[rt],2)%mod*add[rt]%mod + 3*t[rs]*mtag[rt]%mod*Pow(add[rt],2)%mod)%mod;
    tt[ls] = (tt[ls]*Pow(mtag[rt],2)%mod + (len-len/2)*Pow(add[rt],2)%mod + 2*t[ls]*add[rt]*mtag[rt])%mod;
    tt[rs] = (tt[rs]*Pow(mtag[rt],2)%mod + len/2*Pow(add[rt],2)%mod       + 2*t[rs]*add[rt]*mtag[rt])%mod;
    t[ls] = (t[ls]*mtag[rt] + (len-len/2)*add[rt])%mod;
    t[rs] = (t[rs]*mtag[rt] + (len/2)*add[rt])%mod;
    mtag[ls] = (mtag[ls]*mtag[rt])%mod;
    mtag[rs] = (mtag[rs]*mtag[rt])%mod;
    add[ls] = (add[ls]*mtag[rt]%mod+add[rt])%mod;///这个标记也要先乘后加
    add[rs] = (add[rs]*mtag[rt]%mod+add[rt])%mod;
    add[rt] = 0;
    mtag[rt] = 1;
}

void update(int L,int R,int op,ll x,int rt,int l,int r)
{
    if (L<=l && r<=R){
        if (op==1){///+
            add[rt] = (add[rt]+x)%mod;
            ttt[rt] = (ttt[rt] + Pow(x,3)*(r-l+1)%mod + 3*tt[rt]*x%mod + 3*t[rt]*Pow(x,2)%mod)%mod;
            tt[rt] = (tt[rt] + Pow(x,2)*(r-l+1) + 2*t[rt]*x)%mod;
            t[rt] = (t[rt] + (r-l+1)*x)%mod;
        }
        if (op==2){///*
            mtag[rt] = (mtag[rt]*x)%mod;
            add[rt] = (add[rt]*x)%mod; 
            ttt[rt] = (ttt[rt]*Pow(x,3))%mod;
            tt[rt] = (tt[rt]*Pow(x,2))%mod;
            t[rt] = (t[rt]*x)%mod;
        }
        if (op==3){///覆盖
            mtag[rt] = 1,add[rt] = 0;
            ttt[rt] = (r-l+1)*Pow(x,3)%mod;
            tt[rt] = (r-l+1)*Pow(x,2)%mod;
            t[rt] = (r-l+1)*x%mod;
            isset[rt] = x;
        }
        return ;
    }
    mid;
    push_down(rt,r-l+1);
    if (L<=m) update(L,R,op,x,lson);
    if (R>m)  update(L,R,op,x,rson);
    push_up(rt);
}

ll query(int L,int R,ll x,int rt,int l,int r)
{
    if (L<=l && r<=R){
        if (x==1) return t[rt];
        if (x==2) return tt[rt];
        if (x==3) return ttt[rt];
    }
    push_down(rt,r-l+1);
    ll ans = 0;
    mid;
    if (L<=m) ans = (ans+query(L,R,x,lson))%mod;
    if (R>m)  ans = (ans+query(L,R,x,rson))%mod;
    return ans;
}

void build(int rt,int l,int r)
{
    if (l==r){
        t[rt] = tt[rt] = ttt[rt] = add[rt] = isset[rt] = 0;
        mtag[rt] = 1;
        return ;
    }
    mid;
    build(lson);
    build(rson);
    push_up(rt);
}

int main()
{
    int n,q;
    while (~scanf("%d %d",&n,&q),n||q){
        build(1,1,n);
        int op,l,r;
        ll x;
        while (q--){
            scanf("%d %d %d %lld",&op,&l,&r,&x);
            if (op!=4){
                update(l,r,op,x,1,1,n);
            }
            else
                printf("%lld\n",query(l,r,x,1,1,n)%mod);
        }
    }
    return 0;
}

C++版本四

原博客

#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF INT_MAX
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = 10007; 
const int maxn = 100000 + 5;
const int N = 12;
LL add[maxn << 2] , set[maxn << 2] , mul[maxn << 2];
LL sum1[maxn << 2] , sum2[maxn << 2] , sum3[maxn << 2];
void PushUp(int rt)
{
    sum1[rt] = (sum1[rt << 1] + sum1[rt << 1 | 1]) % MOD;
    sum2[rt] = (sum2[rt << 1] + sum2[rt << 1 | 1]) % MOD;
    sum3[rt] = (sum3[rt << 1] + sum3[rt << 1 | 1]) % MOD;
}
void build(int l , int r , int rt)
{
    add[rt] = set[rt] = 0;
    mul[rt] = 1;
    if(l == r) {
        sum1[rt] = sum2[rt] = sum3[rt] = 0;
        return;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    PushUp(rt);
}
void PushDown(int rt , int len)
{
    if(set[rt]) {
        set[rt << 1] = set[rt << 1 | 1] = set[rt];
        add[rt << 1] = add[rt << 1 | 1] = 0;    //注意这个也要下放
        mul[rt << 1] = mul[rt << 1 | 1] = 1;
        LL tmp = ((set[rt] * set[rt]) % MOD) * set[rt] % MOD;
        sum1[rt << 1] = ((len - (len >> 1)) % MOD) * (set[rt] % MOD) % MOD;
        sum1[rt << 1 | 1] = ((len >> 1) % MOD) * (set[rt] % MOD) % MOD;
        sum2[rt << 1] = ((len - (len >> 1)) % MOD) * ((set[rt] * set[rt]) % MOD) % MOD;
        sum2[rt << 1 | 1] = ((len >> 1) % MOD) * ((set[rt] * set[rt]) % MOD) % MOD;
        sum3[rt << 1] = ((len - (len >> 1)) % MOD) * tmp % MOD;
        sum3[rt << 1 | 1] = ((len >> 1) % MOD) * tmp % MOD;
        set[rt] = 0;
    }
    if(mul[rt] != 1) {    //这个就是mul[rt] != 1 , 当时我这里没注意所以TLE了
        mul[rt << 1] = (mul[rt << 1] * mul[rt]) % MOD;
        mul[rt << 1 | 1] = (mul[rt << 1 | 1] * mul[rt]) % MOD;
        if(add[rt << 1])    //注意这个也要下放
            add[rt << 1] = (add[rt << 1] * mul[rt]) % MOD;
        if(add[rt << 1 | 1])
            add[rt << 1 | 1] = (add[rt << 1 | 1] * mul[rt]) % MOD;
        LL tmp = (((mul[rt] * mul[rt]) % MOD * mul[rt]) % MOD);
        sum1[rt << 1] = (sum1[rt << 1] * mul[rt]) % MOD;
        sum1[rt << 1 | 1] = (sum1[rt << 1 | 1] * mul[rt]) % MOD;
        sum2[rt << 1] = (sum2[rt << 1] % MOD) * ((mul[rt] * mul[rt]) % MOD) % MOD;
        sum2[rt << 1 | 1] = (sum2[rt << 1 | 1] % MOD) * ((mul[rt] * mul[rt]) % MOD) % MOD;
        sum3[rt << 1] = (sum3[rt << 1] % MOD) * tmp % MOD;
        sum3[rt << 1 | 1] = (sum3[rt << 1 | 1] % MOD) * tmp % MOD;
        mul[rt] = 1;
    }
    if(add[rt]) {
        add[rt << 1] += add[rt];    //add是+= , mul是*=
        add[rt << 1 | 1] += add[rt];
        LL tmp = (add[rt] * add[rt] % MOD) * add[rt] % MOD;        //注意sum3 , sum2 , sum1的先后顺序
        sum3[rt << 1] = (sum3[rt << 1] + (tmp * (len - (len >> 1)) % MOD) + 3 * add[rt] * ((sum2[rt << 1] + sum1[rt << 1] * add[rt]) % MOD)) % MOD;
        sum3[rt << 1 | 1] = (sum3[rt << 1 | 1] + (tmp * (len >> 1) % MOD) + 3 * add[rt] * ((sum2[rt << 1 | 1] + sum1[rt << 1 | 1] * add[rt]) % MOD)) % MOD;
        sum2[rt << 1] = (sum2[rt << 1] + ((add[rt] * add[rt] % MOD) * (len - (len >> 1)) % MOD) + (2 * sum1[rt << 1] * add[rt] % MOD)) % MOD;
        sum2[rt << 1 | 1] = (sum2[rt << 1 | 1] + (((add[rt] * add[rt] % MOD) * (len >> 1)) % MOD) + (2 * sum1[rt << 1 | 1] * add[rt] % MOD)) % MOD;
        sum1[rt << 1] = (sum1[rt << 1] + (len - (len >> 1)) * add[rt]) % MOD;
        sum1[rt << 1 | 1] = (sum1[rt << 1 | 1] + (len >> 1) * add[rt]) % MOD;
        add[rt] = 0;
    }
}
void update(int L , int R , int c , int ch , int l , int r , int rt)
{
    if(L <= l && R >= r) {
        if(ch == 3) {
            set[rt] = c;
            add[rt] = 0;
            mul[rt] = 1;
            sum1[rt] = ((r - l + 1) * c) % MOD;
            sum2[rt] = ((r - l + 1) * ((c * c) % MOD)) % MOD;
            sum3[rt] = ((r - l + 1) * (((c * c) % MOD) * c % MOD)) % MOD;
        } else if(ch == 2) {
            mul[rt] = (mul[rt] * c) % MOD;
            if(add[rt])
                add[rt] = (add[rt] * c) % MOD;
            sum1[rt] = (sum1[rt] * c) % MOD;
            sum2[rt] = (sum2[rt] * (c * c % MOD)) % MOD;
            sum3[rt] = (sum3[rt] * ((c * c % MOD) * c % MOD)) % MOD;
        } else if(ch == 1) {
            add[rt] += c;
            LL tmp = (((c * c) % MOD * c) % MOD * (r - l + 1)) % MOD;    //(r - l + 1) * c^3
            sum3[rt] = (sum3[rt] + tmp + 3 * c * ((sum2[rt] + sum1[rt] * c) % MOD)) % MOD;
            sum2[rt] = (sum2[rt] + (c * c % MOD * (r - l + 1) % MOD) + 2 * sum1[rt] * c) % MOD;
            sum1[rt] = (sum1[rt] + (r - l + 1) * c) % MOD;
        }
        return;
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    if(L > m)
        update(L , R , c , ch , rson);
    else if(R <= m)
        update(L , R , c , ch , lson);
    else {
        update(L , R , c , ch , lson);
        update(L , R , c , ch , rson);
    }
    PushUp(rt);
}
LL query(int L , int R , int p , int l , int r , int rt)
{
    if(L <= l && R >= r) {
        if(p == 1)
            return sum1[rt] % MOD;
        else if(p == 2)
            return sum2[rt] % MOD;
        else
            return sum3[rt] % MOD;
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    if(L > m)
        return query(L , R , p , rson);
    else if(R <= m)
        return query(L , R , p , lson);
    else 
        return (query(L , R , p , lson) + query(L , R , p , rson)) % MOD;
}
int main()
{
    int n , m;
    int a , b , c , ch;
    while(~scanf("%d %d" , &n , &m))
    {
        if(n == 0 && m == 0)
            break;
        build(1 , n , 1);
        while(m--) {
            scanf("%d %d %d %d" , &ch , &a , &b , &c);
            if(ch != 4) {
                update(a , b , c , ch , 1 , n , 1);
            } else {
                printf("%I64d\n" , query(a , b , c , 1 , n , 1));
            }
        }
    }
    return 0;
}

C++版本五

题解:

我只能说这题很迷,迷之WA,这题我陆陆续续做了4天才AC,其中WA了3页,共计40多次吧,重写代码3次,用各种不同方法写。。最后无奈看着别人的博客照着一个大佬的写就AC了。。吐血,一开始我打算用3个v,3个tag来写,3个v表示区间的一二三次方值,tag分别表示加,乘等于的标记,先处理等,如果有等号标记,区间更新,清除加号和乘号标记,在处理乘和加之前看子区间有没有等号标记,有就先处理子区间的等号标记,然后处理乘,如果同时有加号标记把加的值乘上一个要乘的数,最后处理乘号标记,至于一次方二次方三次方公式是搞数学的老刘推的。。结果就是我样例过了,自己测的几组也过了还是WA,各种迷,怎么修改都是WA,后来看到一个大佬的没有推公式也没有储存三次方。。方法很神奇,而且速度比一般用储存3个值的那种快得多。。

说一下思路:

同样tag1表示加号标记,tag2表示乘,tag3表示等,无疑在向下更新的时候等号的优先级应该最高,先处理等号标记,并把加号和乘号标记置为0和1(初始值),然后重点来了,在处理乘号标记的时候,如果发现子区间有等号标记,直接修改等号标记,否则先将子区间pushdwon一下清空标记,再进行该子区间标记,加号同理,如果子区间有等号标记,就修改等号标记,否则将子区间pushdown清空标记,再将该子区间标记,所有操作完都要清空当前区间标记,然后修改的时候也差不多,先检查该区间有没有等号标记,有的话直接修改等号标记,否则pushdown清空该区间标记,再进行各种标记,查询的时候是整个算法的精髓,他是查询到要查询区间的子区间的等号标记不为初始标记,即为一段相同的数字的时候停止,然后返回该区间的值,进行各个子区间累加,得出答案。。。。一开始我还以为会超时,结果居然比一般的算法快得多,膜拜大佬
 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<string>
#include<stdio.h>
#include<queue>
#include<stack>
#include<map>
#include<deque>
using namespace std;
#define left k*2
#define right k*2+1
const int N=10007;
struct node
{
    int l,r;
    int tag1,tag2,tag3;//分别表示加号,乘号,等号标记
}t[100005*4];
int n;
void Build(int l,int r,int k)
{
    t[k].l=l;
    t[k].r=r;
    t[k].tag1=0;
    t[k].tag2=1;
    t[k].tag3=-1;
    if(l==r)
    {
        t[k].tag3=0;//最底层要赋值为0
        return;
    };
    int mid=(l+r)/2;
    Build(l,mid,left);
    Build(mid+1,r,right);
}
void pushdown(int k)
{
    if(t[k].l==t[k].r)//没有子区间了不用退了
        return;
    if(t[k].tag3!=-1)//处理等号
    {
        t[left].tag3=t[right].tag3=t[k].tag3;//更新子区间等号标记
        t[left].tag2=t[right].tag2=1;
        t[left].tag1=t[right].tag1=0;//清空子区间加乘标记
        t[k].tag3=-1;
        return;
    }
    if(t[k].tag2!=1)//处理乘号
    {
        if(t[left].tag3!=-1)//如果子区间有等号标记,直接修改等号标记
            t[left].tag3=(t[left].tag3*t[k].tag2)%N;
        else//否则清空该子区间标记,进行子区间标记
        {
            pushdown(left);
            t[left].tag2=(t[left].tag2*t[k].tag2)%N;
        }
        if(t[right].tag3!=-1)//同理处理右区间
            t[right].tag3=(t[right].tag3*t[k].tag2)%N;
        else
        {
            pushdown(right);
            t[right].tag2=(t[right].tag2*t[k].tag2)%N;
        }
        t[k].tag2=1;
    }
    if(t[k].tag1!=0)//处理加号标记,和上面同理处理
    {
        if(t[left].tag3!=-1)
            t[left].tag3=(t[left].tag3+t[k].tag1)%N;
        else
        {
            pushdown(left);
            t[left].tag1=(t[left].tag1+t[k].tag1)%N;
        }
        if(t[right].tag3!=-1)
            t[right].tag3=(t[right].tag3+t[k].tag1)%N;
        else
        {
            pushdown(right);
            t[right].tag1=(t[right].tag1+t[k].tag1)%N;
        }
        t[k].tag1=0;//记得还原
    }
}
void update(int l,int r,int v,int d,int k)
{
    if(t[k].l==l&&t[k].r==r)
    {
        if(d==1)
        {
            if(t[k].tag3!=-1)//如果有等号标记,就直接修改等号标记
            {
                t[k].tag3=(t[k].tag3+v%N)%N;
            }
            else
            {
                pushdown(k);//否则清空该区间,进行标记
                t[k].tag1=(t[k].tag1+v%N)%N;
            }
        }
        else if(d==2)//同理
        {
            if(t[k].tag3!=-1)
            {
                t[k].tag3=(t[k].tag3*v%N)%N;
            }
            else
            {
                pushdown(k);
                t[k].tag2=(t[k].tag2*v%N)%N;
            }
        }
        else
        {
            t[k].tag3=v%N;
            t[k].tag1=0;
            t[k].tag2=1;
        }
        return;
    }
    pushdown(k);//向下更新
    int mid=(t[k].l+t[k].r)/2;
    if(r<=mid)
        update(l,r,v,d,left);
    else if(l>mid)
        update(l,r,v,d,right);
    else
    {
        update(l,mid,v,d,left);
        update(mid+1,r,v,d,right);
    }
}
int query(int l,int r,int p,int k)//查询
{
    if(t[k].l>=l&&t[k].r<=r&&t[k].tag3!=-1)//查到是查询区间的子区间且一段全为相同的数
    {
        int temp=1;
        for(int i=1;i<=p;i++)
            temp=(temp*t[k].tag3)%N;
        return ((t[k].r-t[k].l+1)%N*temp)%N;//注意要乘上长度
    }
    pushdown(k);
    int mid=(t[k].l+t[k].r)/2;
    if(r<=mid)
        return query(l,r,p,left)%N;
    else if(l>mid)
        return query(l,r,p,right)%N;
    else
    {
        return (query(l,mid,p,left)+query(mid+1,r,p,right))%N;
    }
}
int main()
{
    int i,j,k,m,d,x,y,c;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        Build(1,n,1);
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d%d",&d,&x,&y,&c);
            if(d>=1&&d<=3)
            {
                update(x,y,c,d,1);
            }
            else
            {
                printf("%d\n",query(x,y,c,1)%N);
            }
        }
    }
    return 0;
}