题目描述:
Yuanfang is puzzled with the question below:
There are n integers, a 1, a 2, …, a n. The initial values of them are 0. There are four kinds of operations.
Operation 1: Add c to each number between a x and a y inclusive. In other words, do transformation a k<—a k+c, k = x,x+1,…,y.
Operation 2: Multiply c to each number between a x and a y inclusive. In other words, do transformation a k<—a k×c, k = x,x+1,…,y.
Operation 3: Change the numbers between a x and a y to c, inclusive. In other words, do transformation a k<—c, k = x,x+1,…,y.
Operation 4: Get the sum of p power among the numbers between a x and a y inclusive. In other words, get the result of a x p+a x+1 p+…+a y p.
Yuanfang has no idea of how to do it. So he wants to ask you to help him.
Input
There are no more than 10 test cases.
For each case, the first line contains two numbers n and m, meaning that there are n integers and m operations. 1 <= n, m <= 100,000.
Each the following m lines contains an operation. Operation 1 to 3 is in this format: “1 x y c” or “2 x y c” or “3 x y c”. Operation 4 is in this format: “4 x y p”. (1 <= x <= y <= n, 1 <= c <= 10,000, 1 <= p <= 3)
The input ends with 0 0.
Output
For each operation 4, output a single integer in one line representing the result. The answer may be quite large. You just need to calculate the remainder of the answer when divided by 10007.
Sample Input
5 5
3 3 5 7
1 2 4 4
4 1 5 2
2 2 5 8
4 3 5 3
0 0
Sample Output
307
7489
题意:给你n个初始化为0的数,然后给你m个操作,每行操作对应四个整数type u v num
,四种操作类型:
type=1:把区间[u,v]
所有数都+num。
type=2:把区间[u,v]
所有数都*num。
type=3:把区间[u,v]
所有数都赋值为num。
type=4:输出区间[u,v]
所有数的num
次方和(1<=num<=3)。
思路:更新的时候涉及到如果两种或三种标记同时存在的时候如何处理。
在这里我选择优先处理赋值操作,因为一个区间如果一旦经过赋值操作以后,add标记和mult标记自然而然地需要变成0。
然后是加法和乘法的先后问题,在这里我选择在乘法操作中加一点小小的处理,如果在处理当前区间的过程中发现存在加法标记add,那么把add标记变成add*num,然后再执行乘法操作。
这样一来,在pushdown()
过程中就一定是最先处理same,然后是multi,最后是add。
WA了很多发,检查到最后,发现,仅仅是忘了模。心态崩了。
附上AC代码:
//
// main.cpp
// L
//
// Created by LucienShui on 2017/6/2.
// Copyright © 2017年 LucienShui. All rights reserved.
//
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define memset(a,b,n) memset(a,b,n*sizeof(a[0]))
#define il inline
#define ll long long
#define ull unsigned long long
using namespace std;
#define ls (u<<1)
#define rs (u<<1|1)
#define lson u<<1,l,mid
#define rson u<<1|1,mid+1,r
#define MOD 10007
#define maxn 100007
int add[maxn<<2],mult[maxn<<2],same[maxn<<2],sum[maxn<<2][4],sz[maxn<<2],sum1,sum2,sum3,tmp2,tmp3;
//add加法标记,mult乘法标记,same赋值标记,sum线段树节点,sz每个节点对应的区间长度
void fun_add(int u, int num) {
add[u] = (add[u]+num)%MOD;
sum1 = sum[u][1],sum2 = sum[u][2],sum3 = sum[u][3];
sum[u][1] += (num*sz[u])%MOD;//更新一次方的和
sum[u][1] %= MOD;
tmp2 = (num * num)%MOD;
sum[u][2] += sum1*num*2%MOD + (tmp2*sz[u])%MOD;//根据完全平方公式更新二次方的和
sum[u][2] %= MOD;
tmp3 = (tmp2 * num)%MOD;
sum[u][3] += (3*tmp2*sum1)%MOD + (3*sum2*num)%MOD + (tmp3*sz[u])%MOD;//根据完全立方公式和更新三次方的和
sum[u][3] %= MOD;
}
void fun_mult(int u,int num) {
if(mult[u]) mult[u] = (mult[u]*num)%MOD;
else mult[u] = num;
add[u] = (add[u]*num)%MOD;//如果当前节点存在加法标记,奖其更改为add*num
sum1 = sum[u][1],sum2 = sum[u][2],sum3 = sum[u][3];
sum[u][1] = (sum1*num)%MOD;
tmp2 = (num*num)%MOD;
sum[u][2] = (sum2*tmp2)%MOD;
tmp3 = (tmp2*num)%MOD;
sum[u][3] = (sum3*tmp3)%MOD;
}
void fun_same(int u, int num) {
same[u] = num;
add[u] = mult[u] = 0;
sum[u][1] = (num*sz[u])%MOD;
tmp2 = (num*num)%MOD;
sum[u][2] = (tmp2*sz[u])%MOD;
tmp3 = (tmp2*num)%MOD;
sum[u][3] = (tmp3*sz[u])%MOD;
}
void pushup(int u) {//从子树更新父节点
sum[u][1] = (sum[ls][1] + sum[rs][1])%MOD;
sum[u][2] = (sum[ls][2] + sum[rs][2])%MOD;
sum[u][3] = (sum[ls][3] + sum[rs][3])%MOD;
}
void pushdown(int u) {//清除三种lazy标记
if(same[u]) {
fun_same(ls,same[u]);
fun_same(rs,same[u]);
same[u]=0;
}
if(mult[u]) {
fun_mult(ls,mult[u]);
fun_mult(rs,mult[u]);
mult[u]=0;
}
if(add[u]) {
fun_add(ls,add[u]);
fun_add(rs,add[u]);
add[u]=0;
}
}
void build(int u, int l, int r) {//递归建树
if(l==r) {
add[u] = mult[u] = same[u] = 0;
sum[u][1] = sum[u][2] = sum[u][3] = 0;
sz[u] = 1;
return ;
}
add[u] = mult[u] = same[u] = 0;
sum[u][1] = sum[u][2] = sum[u][3] = 0;
int mid = (l+r)>>1;
build(lson);
build(rson);
sz[u] = sz[ls] + sz[rs];//记得向上回溯sz数组
}
void update(int u, int l, int r, int b, int e, int num, int type) {
if(b <= l && r <= e) {
if(type==1) fun_add(u,num);
else if(type==2) fun_mult(u,num);
else fun_same(u,num);
return ;
}
pushdown(u);
int mid = (l+r)>>1;
if(b<=mid) update(lson,b,e,num,type);
if(e>mid) update(rson,b,e,num,type);
pushup(u);
}
int query(int u, int l, int r, int b, int e, int pow) {
if(b <= l && r<=e) return sum[u][pow];
pushdown(u);
int mid = (l+r)>>1;
if(e<=mid) return query(lson,b,e,pow)%MOD;//记得模MOD
else if(b>mid) return query(rson,b,e,pow)%MOD;
return (query(lson,b,e,pow)+query(rson,b,e,pow))%MOD;
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
int n,m;
while(scanf("%d%d",&n,&m),n!=0&&m!=0) {
int type,b,e,num;
build(1,1,n);
for(int i=1 ; i<=m ; i++) {
scanf("%d%d%d%d",&type,&b,&e,&num);
if(type==4) printf("%d\n",query(1,1,n,b,e,num));
else update(1,1,n,b,e,num,type);
}
}
return 0;
}