Transformation(三重标记线段树)

题目传送门

Transformation

题目大意

含n个数字的的数列a各数字初值均为0,对其进行m次操作,每次操作可为下列之一:
1   x   y   c 1\ x\ y\ c 1 x y c a x a_x ax a y a_y ay间的数字(含边界)均增加c
2   x   y   c 2\ x\ y\ c 2 x y c a x a_x ax a y a_y ay间的数字(含边界)均乘以c
3   x   y   c 3\ x\ y\ c 3 x y c a x a_x ax a y a_y ay间的数字(含边界)均变为c
4   x   y   p 4\ x\ y\ p 4 x y p:输出 a x a_x ax a y a_y ay间的数字(含边界)的p次方之和
对于每个操作4,输出答案模10007
数据组数<=10。
1 < = n , m < = 1 e 5 , 1 < = x < = y < = n 1<=n,m<=1e5,1<=x<=y<=n 1<=n,m<=1e51<=x<=y<=n
1 < = c < = 1 e 4 , 1 < = p < = 3 1<=c<=1e4,1<=p<=3 1<=c<=1e41<=p<=3
输入 0 0结束

思路

显然线段树,区间修改,区间查询
麻烦就在查询的地方为p次方之和,但是 1 < = p < = 3 1<=p<=3 1<=p<=3,所以我们可以选择分别维护p的一次方,二次方,三次方的和
lazy标记也相应的标记,修改,乘,加
lazy标记下传的时候的顺序显然应该是
1、修改,然后将乘法标记变成1,加法标记变成0
2、乘
3、加

三个次方的维护为:
s u m 1 = x 1 + x 2 + . . . + x n sum1 = x_1 +x_2 + ...+ x_n sum1=x1+x2+...+xn
s u m 2 = x 1 2 + x 2 2 + . . . + x n 2 sum2 = x_1^2 +x_2^2 + ... +x_n^2 sum2=x12x22+...+xn2
s u m 3 = x 1 3 + x 2 3 + . . . + x n 3 sum3 = x_1^3 + x_2^3 + ... + x_n^3 sum3=x13+x23+...+xn3

进行相应操作时的变化
加:
s u m 1 = ( x 1 + k ) + ( x 2 + k ) + . . . + ( x n + k ) = s u m 1 + n k sum1=(x_1 +k) +(x_2 +k) + ...+(x_n + k)= sum1 + nk sum1=(x1+k)+(x2+k)+...+(xn+k)=sum1+nk
s u m 2 = ( x 1 + k ) 2 + ( x 2 + k ) 2 + . . . + ( x n + k ) 2 = s u m 2 + 2 k ∗ s u m 1 + n k 2 sum2=(x_1 + k)^2 +(x_2 +k)^2 +...+(x_n + k)^2= sum2 + 2k*sum1 + nk^2 sum2=(x1+k)2+(x2+k)2+...+(xn+k)2=sum2+2ksum1+nk2
s u m 3 = ( x 1 + k ) 3 + ( x 2 + k ) 3 + . . . + ( x n + k ) 3 = s u m 3 + n k 3 + 3 k ∗ s u m 2 + 3 ∗ k 2 s u m 1 sum3=(x_1 +k)^3 +(x_2 +k)^3 + ...+(x_n + k)^3=sum3 + nk^3 + 3k*sum2 + 3*k^2sum1 sum3=(x1+k)3+(x2+k)3+...+(xn+k)3=sum3+nk3+3ksum2+3k2sum1

乘:
s u m 1 = s u m 1 ∗ k sum1= sum1 * k sum1=sum1k
s u m 2 = s u m 2 ∗ k 2 sum2 = sum2 * k^2 sum2=sum2k2
s u m 3 = s u m 3 ∗ k 3 sum3= sum3 * k^3 sum3=sum3k3

修改:
s u m 1 = n k sum1= nk sum1=nk
s u m 2 = n ∗ k 2 sum2=n*k^2 sum2=nk2
s u m 3 = n ∗ k 3 sum3=n* k^3 sum3=nk3

AC Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define debug(a) cout<<#a<<"="<<a<<endl;
#define INF 0x3f3f3f3f
const int M=10007;
const int N=1e5 +9;
int n, m , c, x, y, v;
struct segtree{
    int s1, s2, s3;
    int lazya, lazym, lazyc;
    void clear(){
        s1=s2=s3=0;
        lazya=lazyc=0;
        lazym=1;
    }
}tr[N<<2];
inline int lc(int p) {return p<<1;}
inline int rc(int p) {return p<<1|1;}
inline void push_up(int p){
    tr[p].s1=(tr[lc(p)].s1+tr[rc(p)].s1)%M;
    tr[p].s2=(tr[lc(p)].s2+tr[rc(p)].s2)%M;
    tr[p].s3=(tr[lc(p)].s3+tr[rc(p)].s3)%M;
}
inline void build(int p, int l, int r){ 
    tr[p].clear();
	if(l==r) return ;
	int mid=(l+r)>>1;
	build(lc(p), l, mid);
	build(rc(p), mid+1, r);
}
inline void f(int f, int p, int len){
    int k;
	if(tr[f].lazyc){
        k=tr[f].lazyc;
        tr[p].s3=len*k*k*k%M;
        tr[p].s2=len*k*k%M;
        tr[p].s1=len*k%M;
        tr[p].lazya=0;
        tr[p].lazym=1;
        tr[p].lazyc=k;
    }
    if(tr[f].lazym!=1){
        k=tr[f].lazym;
        tr[p].s3=k*k*k*tr[p].s3%M;
        tr[p].s2=k*k*tr[p].s2%M;
        tr[p].s1=k*tr[p].s1%M;
        tr[p].lazya=k*tr[p].lazya%M;
        tr[p].lazym=k*tr[p].lazym%M;
    }
    if(tr[f].lazya){
        k=tr[f].lazya;
        tr[p].s3=(tr[p].s3 + len*k*k*k + 3*k*tr[p].s2 + 3*k*k*tr[p].s1)%M;
        tr[p].s2=(tr[p].s2 + len*k*k + 2*k*tr[p].s1)%M;
        tr[p].s1=(tr[p].s1 + len*k)%M;
        tr[p].lazya=(tr[p].lazya + k)%M;
    }
}
inline void push_down(int p, int lenl, int lenr){
	f(p, lc(p), lenl);
	f(p, rc(p), lenr);
	tr[p].lazya=tr[p].lazyc=0;
    tr[p].lazym=1;
}
inline void updata(int p, int l, int r, int x, int y, int k){
	if(l<=x && y<=r){
        int len=y-x+1;
        if(c==1){
            tr[p].lazya=(tr[p].lazya+k)%M;
            tr[p].s3=(tr[p].s3 + len*k*k*k + 3*k*tr[p].s2 + 3*k*k*tr[p].s1)%M;
            tr[p].s2=(tr[p].s2 + 2*k*tr[p].s1 + len*k*k)%M;
            tr[p].s1=(tr[p].s1 + len*k)%M;
        }
        else if(c==2){
            tr[p].lazya=tr[p].lazya*k%M;
            tr[p].lazym=tr[p].lazym*k%M;
            tr[p].s3=k*k*k*tr[p].s3%M;
            tr[p].s2=k*k*tr[p].s2%M;
            tr[p].s1=k*tr[p].s1%M;
        }
        else{
            tr[p].lazyc=k;
            tr[p].lazya=0;
            tr[p].lazym=1;
            tr[p].s3=len*k*k*k%M;
            tr[p].s2=len*k*k%M;
            tr[p].s1=len*k%M;
        }
		return ;
	}
	int mid=(x+y)>>1;
    push_down(p, mid-x+1, y-mid);
	if(l<=mid) updata(lc(p), l, r, x, mid, k);
	if(r>mid)  updata(rc(p), l, r, mid+1, y, k);
    push_up(p);
}

inline int query(int p, int l, int r, int x, int y){
	if(l<=x && y<=r){
        if(v==1)      return tr[p].s1;
        else if(v==2) return tr[p].s2;
        else          return tr[p].s3;
    }
    int mid=(x+y)>>1;
    push_down(p, mid-x+1, y-mid);
    int ans=0;
    if(l<=mid) ans=(ans+query(lc(p), l, r, x, mid))%M;
    if(r>mid)  ans=(ans+query(rc(p), l, r, mid+1, y))%M;
    return ans;
}
signed main(){
    while(~scanf("%lld%lld", &n, &m)&&(n||m)){
        build(1,1,n);
        for(int i=1; i<=m; i++){
            scanf("%lld%lld%lld%lld", &c, &x, &y, &v);
            if(c==4) printf("%lld\n", query(1,x,y,1,n));
            else     updata(1,x,y,1,n,v);
        }
    }
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值