又是一道很裸的线段树,一个数列a1, a2, …, an,然后4种操作:
1,x,y,c:将ax到ay之间的数都加c
2,x,y,c:将ax到ay之间的数都乘以c
3,x,y,c:将ax到ay之间的数变成c
4,x,y,p:求出ax到ay之间数字的p次幂的和,p=1,2,3,结果对10007取模
首先肯定要先保存3个次幂的和,然后对于每个结点用a和b作标记,f表示需要pushdown,则每个数i可以表示成ai+b
把上面三个操作做个统一,就是输入给一组(j,k),计算j(ai+b)+k=j*ai + j*b+k,并将系数重新赋值给a和b
三种操作的参数如下:
1:(1,c)
2:(c,0)
3:(0,c)
然后是传入(j,k)三个和的变化,这个公式也不难推导,但要注意计算的顺序应该是从高次往低次更新,因为高次的计算总要利用到低次的结果每次pushdown后a=1,b=0,f=0
剩下就只是实现上的细节了
PS:因为各种脑残手抽WA了几次才A,以后还是要注意细节方面的问题
//HDU 4578 3671MS 9952K 2560B G++
//Author: hongrock
#include<cstdio>
#include<cstring>
#define LEFT(a) ((a)<<1)
#define RIGHT(a) (((a)<<1)|1)
#define MID(a,b) (((a)+(b))>>1)
#define MAXN 400010
#define MOD 10007
int n, q, op, x, y, c, s, l[MAXN], r[MAXN], a[MAXN], b[MAXN], sum[MAXN][3];
bool f[MAXN];
char ch;
int getnum(){
s=0;
ch=getchar();
while(ch<48 || ch>57) ch=getchar();
while(ch>=48 && ch<=57){
s = s*10+ch-48;
ch = getchar();
}
return s;
}
void build(int o, int ll, int rr){
l[o]=ll;
r[o]=rr;
a[o]=1;
if(ll<rr){
int m = MID(ll,rr);
build(LEFT(o), ll, m);
build(RIGHT(o), m+1, rr);
}
}
void maintain(int o){
for(int i=0; i<3; i++) sum[o][i] = (sum[LEFT(o)][i]+sum[RIGHT(o)][i])%MOD;
}
void pushdown(int o);
void update(int o, int ll, int rr, int j, int k){
if(l[o]==ll && r[o]==rr){
int j1,j2,j3,k1,k2,k3;
j1=j;
j2=(j*j1)%MOD;
j3=(j*j2)%MOD;
k1=k;
k2=(k*k1)%MOD;
k3=(k*k2)%MOD;
sum[o][2] = (j3*sum[o][2])%MOD + (((j2*k1)%MOD*3)%MOD*sum[o][1])%MOD + (((j1*k2)%MOD*3)%MOD*sum[o][0])%MOD + ((rr-ll+1)*k3)%MOD;
sum[o][2]%=MOD;
sum[o][1] = (j2*sum[o][1])%MOD + (((j1*k1)%MOD*2)%MOD*sum[o][0])%MOD + ((rr-ll+1)*k2)%MOD;
sum[o][1]%=MOD;
sum[o][0] = (j1*sum[o][0])%MOD + ((rr-ll+1)*k1)%MOD;
sum[o][0]%=MOD;
a[o] = (a[o]*j)%MOD;
b[o] = ((j*b[o])%MOD + k)%MOD;
f[o] = 1;
}
else{
if(f[o]) pushdown(o);
int m = MID(l[o],r[o]);
if(m<ll) update(RIGHT(o), ll, rr, j, k);
else if(m>=rr) update(LEFT(o), ll, rr, j, k);
else{
update(LEFT(o), ll, m, j, k);
update(RIGHT(o), m+1, rr, j, k);
}
maintain(o);
}
}
void pushdown(int o){
int m = MID(l[o],r[o]);
update(LEFT(o), l[o], m, a[o], b[o]);
update(RIGHT(o), m+1, r[o], a[o], b[o]);
a[o]=1;
b[o]=0;
f[o]=0;
}
int query(int o, int ll, int rr, int p){
if(l[o]==ll && r[o]==rr) return sum[o][p];
if(f[o]) pushdown(o);
int tmp, m=MID(l[o], r[o]);
if(m<ll) tmp = query(RIGHT(o), ll, rr, p);
else if(m>=rr) tmp = query(LEFT(o), ll, rr, p);
else{
tmp = (query(LEFT(o), ll, m, p)+query(RIGHT(o), m+1, rr, p))%MOD;
}
maintain(o);
return tmp;
}
int main(){
while(1){
n=getnum();
q=getnum();
if(!(n||q)) break;
memset(sum, 0, sizeof(sum));
memset(b, 0, sizeof(b));
memset(f, 0, sizeof(f));
build(1, 1, n);
while(q--){
op=getnum();
x=getnum();
y=getnum();
c=getnum();
if(op==1) update(1, x, y, 1, c);
else if(op==2) update(1, x, y, c, 0);
else if(op==3) update(1, x, y, 0, c);
else printf("%d\n", query(1, x, y, c-1));
}
}
return 0;
}