【线段树多符号区间更新】HDU

来源:互联网 发布:mac brew mongodb 编辑:程序博客网 时间:2024/06/08 01:33

Problem Description

输入n,m。给你长度为n的数组,初始化为0。接下里有m行操作:
(1)”1 x y c”,代表 把区间 [x,y] 上的值全部加c

(2)”2 x y c”,代表 把区间 [x,y] 上的值全部乘以c

(3)”3 x y c” 代表 把区间 [x,y]上的值全部赋值为c

(4)”4 x y p” 代表 求区间 [x,y] 上值的p次方和1<=p<=3

思路:

参考了一个我觉得很好的博客,但是有点不足的是,它的立方和那里错了
链接:http://www.cnblogs.com/GBRgbr/archive/2013/08/13/3254442.html。建议在敲的时候先别取mod,这样代码会清晰特别特别多。等敲好了,样例过了。在取模,这样就不会乱了,思路清晰还是很好敲的。

#include<bits/stdc++.h>using namespace std;#define lson root<<1#define rson root<<1|1#define MID int mid = (l + r) / 2#define N 100000#define mod 10007int sum[3][N<<2], flag[2][N<<2];//sum[0]-[2]分别代表一次,二次,三次方后的和。//flag[0]标记+了多少,flag[1]标记乘了多少void build(int root, int l, int r)//初始化{    flag[0][root] = 0;    flag[1][root] = 1;//乘1还是本身    sum[0][root] = sum[1][root] = sum[2][root] = 0;    if(l == r)        return;    MID;    build(lson, l, mid);    build(rson, mid + 1, r);}void Merge(int root, int l, int r)//归并和{    for(int i = 0; i < 3; i++)    {        sum[i][root] = (sum[i][lson] + sum[i][rson]) % mod;    }}void add(int root, int l, int r, int c)//区间l-r都加c{    if(c){    int s0 = sum[0][root], s1 = sum[1][root];    //这些公式 纸上推一推就出来了    sum[0][root] = (s0 + ((r-l+1)%mod * c) % mod) % mod;    //取掉mod后就特别清晰 s0+(r-l+1)*c    sum[1][root] = (s1 + ((2*c)%mod * s0)%mod + ((((r-l+1)%mod*c)%mod)*c%mod)%mod) % mod;    //s1+(2*c)*s0+(r-l+1)*c*c    sum[2][root] = (sum[2][root] + (3*c%mod * s1)%mod + ((3*c%mod * c)%mod * s0)%mod + ((((r-l+1)%mod * c)%mod * c)%mod * c)%mod)%mod;    //sum[2][root]+3*c*s1+3*c*c*s0+(r-l+1)*c*c*c    }    return;}void multi(int root, int l, int r, int v)//区间l-r都乘v{    if(v != 1){//不是1才乘,乘法就特别简单了。        int x = v;        sum[0][root] *= x;// 乘了x一次方        sum[0][root] %= mod;        x *= v;        x %= mod;        sum[1][root] *= x;// 乘了x二次方        sum[1][root] %= mod;        x *= v;        x %= mod;        sum[2][root] *= x;// 乘了x立方        sum[2][root] %= mod;    }    return;}void pushdown(int root, int l, int r)//先乘法后加法。{    MID;    if(flag[1][root] != 1)    {        flag[1][lson] *= flag[1][root];        flag[1][lson] %= mod;        flag[1][rson] *= flag[1][root];        flag[1][rson] %= mod;        flag[0][lson] *= flag[1][root];        flag[0][lson] %= mod;        flag[0][rson] *= flag[1][root];        flag[0][rson] %= mod;        multi(lson, l, mid, flag[1][root]);        multi(rson, mid + 1, r, flag[1][root]);        flag[1][root] = 1;    }    if(flag[0][root] != 0)    {        flag[0][lson] += flag[0][root];        flag[0][lson] %= mod;        flag[0][rson] += flag[0][root];        flag[0][rson] %= mod;        add(lson, l, mid, flag[0][root]);        add(rson, mid + 1, r, flag[0][root]);        flag[0][root] = 0;    }    return;}void updata(int root, int l, int r, int ul, int ur, int v, int ok){    if(ul <= l && r <= ur)    {        if(ok == 1)//区间加        {            flag[0][root] += v;            flag[0][root] %= mod;            add(root, l, r, v);//更新sum        }        else if(ok == 2)//区间乘        {            flag[0][root] *= v;//将区间加更新,这样pushdown的时候就先乘后加            flag[0][root] %= mod;            flag[1][root] *= v;            flag[1][root] %= mod;            multi(root, l, r, v);//更新sum        }        else//区间全部赋值为v        {            flag[0][root] = v;            flag[1][root] = 0;//为0,因为下面的都没用了。pushdown的时候可以更新掉。            multi(root, l, r, 0);//先乘            add(root, l, r, v);//再加        }        return;    }    pushdown(root, l, r);    MID;    if(ul <= mid) updata(lson, l, mid, ul, ur, v, ok);    if(ur > mid) updata(rson, mid + 1, r, ul, ur, v, ok);    Merge(root, l, r);}int query(int root, int l, int r, int ul, int ur, int p){    if(ul <= l && r <= ur)    {        return sum[p-1][root];//看p就几次方的和    }    pushdown(root, l, r);    MID;    int red = 0;    if(ul <= mid) red += query(lson, l, mid, ul, ur, p) % mod;    if(ur > mid) red += query(rson, mid + 1, r, ul, ur, p) % mod;    return red;}int main(){    int n, m, ok, ul, ur, v;    while(~scanf("%d %d", &n, &m))    {        if(!n && !m) break;        build(1, 1, n);        while(m--)        {            scanf("%d %d %d %d", &ok, &ul, &ur, &v);            if(ok == 4)            {                printf("%d\n", query(1, 1, n, ul, ur, v) % mod);            }            else            {                updata(1, 1, n, ul, ur, v, ok);            }        }    }}