HDU 4578 Transformation[线段树]

http://acm.hdu.edu.cn/showproblem.php?pid=4578
N个数,4种操作。
1. [l,r]区间的每个数加上c
2. [l,r]区间的每个数乘上c
3. [l,r]区间的所有数都设置为c
4. 询问区间[l,r]的数的p次方和 (1p3)

之前做线段树一直很不6,今天自己把这几个维护的式子推了一遍,终于找到点感觉了。
询问的p只有123,分别维护好就行了。操作3等价于乘0再加c。

(ax+b)c=acx+bc

(ax1)p+(ax2)p=ap(xp1+xp2)

(ax1+b)2+(ax2+b)2=(ax1)2+(ax2)2+2b(ax1+ax2)+2b2

(x1+b)3+(x2+b)3=(x31+x32)+3b(x21+x22)+3b2(x1+x2)+2b3


#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

#define MID int mid = (L+R)>>1;
#define CHD int lc = node<<1, rc = node<<1|1;
#define rep(i,f,t) for(int i = f; i <= t; ++i)
int n,m;
typedef long long int64;

const int maxn = 100001<<2;
const int mod = 10007;
struct sgt{
    int64 sum[maxn][4];
    int64 addv[maxn];
    int64 mulv[maxn];
    void init(){ addv[1] = mulv[1] = 0; }
    int tp,v;

    void pushDown(int node){
        CHD;
        if(mulv[node] != 1){
            mulv[lc] = mulv[lc] * mulv[node] % mod;
            mulv[rc] = mulv[rc] * mulv[node] % mod;
            addv[lc] = addv[lc] * mulv[node] % mod;
            addv[rc] = addv[rc] * mulv[node] % mod;
        }
        if(addv[node] != 0){
            addv[lc] = (addv[lc] + addv[node]) % mod;
            addv[rc] = (addv[rc] + addv[node]) % mod;
        }
        mulv[node] = 1;
        addv[node] = 0;
    }

    void maintain(int node,int L,int R){
        CHD;
        if(L != R)
            rep(i,1,3) sum[node][i] = (sum[lc][i] + sum[rc][i]) % mod;

        if(mulv[node] == 0){
            rep(i,1,3)sum[node][i] = 0;
        }else if(mulv[node] != 1){
            sum[node][1] = sum[node][1]*mulv[node]%mod;
            sum[node][2] = sum[node][2]*mulv[node]*mulv[node]%mod;
            sum[node][3] = sum[node][3]*mulv[node]*mulv[node]*mulv[node]%mod;
        }
        if(addv[node]){
        //这三个顺序不能反
            sum[node][3] = ( sum[node][3] + addv[node]*sum[node][2]*3%mod 
                            + addv[node]*addv[node]*sum[node][1]*3%mod
                            + addv[node]*addv[node]*addv[node]%mod*(R-L+1)%mod) % mod;
            sum[node][2] = ( sum[node][2] + addv[node]*sum[node][1]*2%mod 
                            + addv[node]*addv[node]*(R-L+1)%mod) % mod;
            sum[node][1] = ( sum[node][1] + addv[node]*(R-L+1) ) % mod;
        }

        //叶子结点,可以把标记清除
        if(L == R){
            mulv[node] = 1;
            addv[node] = 0;
        }
    }

    void update(int from,int to,int val,int node,int L,int R){
        if(from <= L && R <= to){
            if(tp == 1){
                addv[node] = (addv[node] + val) % mod;
            } else if(tp == 2){
                addv[node] = (addv[node] * val) % mod;
                mulv[node] = (mulv[node] * val) % mod;
            } else {
                addv[node] = val;
                mulv[node] = 0;
            }
            maintain(node,L,R);
            return;
        }
        pushDown(node);
        MID;CHD;
        if(from <= mid) update(from,to,val,lc,L,mid);
        else maintain(lc,L,mid);
        if(to > mid) update(from,to,val,rc,mid+1,R);
        else maintain(rc,mid+1,R);
        maintain(node,L,R);
    }
    int query(int from,int to,int node,int L,int R){
        maintain(node,L,R);
        if(from <= L && R <= to){
            return sum[node][v];
        }
        int ans = 0;
        pushDown(node);
        MID;CHD;
        if(from <= mid) ans += query(from,to,lc,L,mid);
        else    maintain(lc,L,mid);
        if(to > mid)  ans += query(from,to,rc,mid+1,R);
        else    maintain(rc,mid+1,R);
        return ans%mod;
    }
    void run(){
        while(m--){
            int f,t;
            scanf("%d%d%d%d",&tp,&f,&t,&v);
            if(tp == 4){
                int ans = query(f,t,1,1,n);
                printf("%d\n",ans);
            } else {
                update(f,t,v,1,1,n);
            }
        }
    }
}tree;
int main(){
    while(scanf("%d%d",&n,&m), n||m){
        tree.init();
        tree.run();
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2015-04-21 01:16  DSChan  阅读(106)  评论(0)    收藏  举报