题意:给一个序列a[i],初始值均为0,,定义4种操作:
1.将某一段a[i]都加上val
2.将某一段a[i]都乘上val
3.将某一段a[i]都变成val
4.询问某一段的和,平方和,立方和
分析:
很容易想到是线段树处理的题目,并且要用到Lazy思想,一开始的想法是我们可以用sum1,sum2,sum3来维护某段的和,平方和,立方和。然后把每个结点做一个标记(对应操作1,2,3),如果该结点之前存在标记就push_down,但是分析就知道,只要做标记需要递归的push_down(即如果push_down的子树也存在标记就要先处理子树的标记,先将子树push_down),显然效率不高。
再次分析可知,我们可以把每个结点都表示为ax+b的形式,如果是操作1,就是在把b->b+val,操作2就是a->a*val b->b*val,操作3就是a->1,b->0,同时记录下变成的val值c->val,这样的话,我们push_down时就只要push一层即可无需递归,因为可以将子树的ax+b和父亲的ax+b相结合
题目代码有点繁杂,写得时候要细心,特别是push_down的时候,对拍了很多次才A掉。。。
c++代码:
#include<cstdio>
const int MAX = 100020;
const int N = 10007;
int ans;
typedef struct
{
int left,right;
int a,b; //ax+b形式
int c; //记录操作3的值
int num; //num = (r-l+1)
int sum1,sum2,sum3; //分别存1次和,2次和,3次和
} NODE;
NODE tree[3*MAX];
void buildtree(int i,int l,int r)
{
tree[i].left = l;
tree[i].right = r;
tree[i].a = 1;
tree[i].b = tree[i].c = 0;
tree[i].num = (r-l+1);
tree[i].sum1 = tree[i].sum2 = tree[i].sum3 = 0;
if (r - l > 0)
{
int mid = (l+r)>>1;
buildtree(i<<1,l,mid);
buildtree(i<<1|1,mid+1,r);
}
}
inline void calc(int i,int flag,int c)
{
if (flag == 1)
{
tree[i].b = (tree[i].b+c)%N;
tree[i].sum3 = (tree[i].sum3 + tree[i].num*c%N*c%N*c%N+3*tree[i].sum1%N*c%N*c%N+3*tree[i].sum2%N*c%N)%N;
tree[i].sum2 = (tree[i].sum2 + tree[i].num*c%N*c%N+2*c%N*tree[i].sum1%N)%N;
tree[i].sum1 = (tree[i].sum1 + tree[i].num*c)%N;
}
else if (flag == 2)
{
tree[i].a = (tree[i].a*c)%N;
tree[i].b = (tree[i].b*c)%N;
tree[i].sum3 = c*c%N*c%N*tree[i].sum3%N;
tree[i].sum2 = c*c%N*tree[i].sum2%N;
tree[i].sum1 = c*tree[i].sum1%N;
}
else if (flag == 3)
{
tree[i].a = 1;
tree[i].b = 0;
tree[i].c = c;
tree[i].sum3 = tree[i].num*c%N*c%N*c%N;
tree[i].sum2 = tree[i].num*c%N*c%N;
tree[i].sum1 = tree[i].num*c%N;
}
}
void down(int i)
{
int zuo,you,a,b,c;
if (tree[i].num == 1) return;
zuo = i<<1;
you = i<<1|1;
a = tree[i].a;
c = tree[i].c;
b = tree[i].b;
if (c != 0)
{
tree[you].a = tree[zuo].a = a;
tree[you].b = tree[zuo].b = b;
tree[zuo].c = c;
tree[zuo].sum3 = tree[zuo].num*(a*c%N+b)%N*(a*c%N+b)%N*(a*c%N+b)%N;
tree[zuo].sum2 = tree[zuo].num*(a*c%N+b)%N*(a*c%N+b)%N;
tree[zuo].sum1 = tree[zuo].num*(a*c%N+b)%N;
tree[you].c = c;
tree[you].sum3 = tree[you].num*(a*c%N+b)%N*(a*c%N+b)%N*(a*c%N+b)%N;
tree[you].sum2 = tree[you].num*(a*c%N+b)%N*(a*c%N+b)%N;
tree[you].sum1 = tree[you].num*(a*c%N+b)%N;
}
else
{
tree[zuo].a = a * tree[zuo].a%N;
tree[zuo].b = (b + a*tree[zuo].b%N)%N;
tree[zuo].sum3 = (a*a%N*a%N*tree[zuo].sum3%N+3*a%N*a%N*b%N*tree[zuo].sum2%N+
3*a%N*b%N*b%N*tree[zuo].sum1%N+b*b%N*b%N*tree[zuo].num%N)%N;
tree[zuo].sum2 = (a*a%N*tree[zuo].sum2%N+2*a%N*b%N*tree[zuo].sum1%N+b*b%N*tree[zuo].num%N)%N;
tree[zuo].sum1 = (a*tree[zuo].sum1%N+tree[zuo].num*b%N)%N;
tree[you].a = a * tree[you].a%N;
tree[you].b = (b + a*tree[you].b%N)%N;
tree[you].sum3 = (a*a%N*a%N*tree[you].sum3%N+3*a%N*a%N*b%N*tree[you].sum2%N+
3*a%N*b%N*b%N*tree[you].sum1%N+b*b%N*b%N*tree[you].num%N)%N;
tree[you].sum2 = (a*a%N*tree[you].sum2%N+2*a%N*b%N*tree[you].sum1%N+b*b%N*tree[you].num%N)%N;
tree[you].sum1 = (a*tree[you].sum1%N+tree[you].num*b%N)%N;
}
}
void update(int i,int flag,int l,int r,int c)
{
if (tree[i].left == l && tree[i].right == r)
{
calc(i,flag,c);
return;
}
else
{
down(i);
tree[i].a = 1;
tree[i].b = 0;
tree[i].c = 0;
int mid = (tree[i].left+tree[i].right)>>1;
if (r <= mid)
update(i<<1,flag,l,r,c);
else if (l > mid)
update(i<<1|1,flag,l,r,c);
else
{
update(i<<1,flag,l,mid,c);
update(i<<1|1,flag,mid+1,r,c);
}
tree[i].sum1 = (tree[i<<1].sum1 + tree[i<<1|1].sum1)%N;
tree[i].sum2 = (tree[i<<1].sum2 + tree[i<<1|1].sum2)%N;
tree[i].sum3 = (tree[i<<1].sum3 + tree[i<<1|1].sum3)%N;
}
}
void find(int i,int c,int l,int r)
{
if (tree[i].left == l && tree[i].right == r)
{
if (c == 1) ans = ans+tree[i].sum1;
else if (c == 2) ans = ans + tree[i].sum2;
else if (c == 3) ans = ans + tree[i].sum3;
ans = ans % N;
return;
}
down(i);
tree[i].a = 1;
tree[i].b = 0;
tree[i].c = 0;
int mid = (tree[i].left+tree[i].right)>>1;
if (r <= mid)
find(i<<1,c,l,r);
else if (l > mid)
find(i<<1|1,c,l,r);
else
{
find(i<<1,c,l,mid);
find(i<<1|1,c,mid+1,r);
}
}
int main()
{
int n,m,i,x,y,c,flag;
while(scanf("%d%d",&n,&m) == 2)
{
if (n+m==0) break;
buildtree(1,1,n);
for (i = 1; i <= m; i++)
{
scanf("%d%d%d%d",&flag,&x,&y,&c);
if(flag == 4)
{
ans = 0;
find(1,c,x,y);
printf("%d\n",ans);
}
else
update(1,flag,x,y,c%N);
}
}
return 0;
}