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 10007
int 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);
}
}
}
}