HDU 4578 Transformation (线段树)

本来是很裸的线段树,但是如果用lazy操作,情况太多了,很烦躁。需要考虑先加后乘和先乘后加的不同处理。

更新sum值时,考虑对一个区间内的数加上一个数c后对这三个值有什么影响。首先考虑一个数c的情况。一次方就不说了直接加上c*区间长度len就行了。
二次方。一个数开始为a。后来为a+c。则平方后为a*a+2*a*c+c*c。比原来多了2*a*c+c*c。而对于整个区间增加
2*sum[1]*c+len*c*c。三次方增加3*sum[2]*c+3*sum[1]*c*c+len*c*c*c。

代码写的恶心死了.................

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <climits>//形如INT_MAX一类的
#define MAX 100050
#define INF 0x7FFFFFFF
#define REP(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define L(x) x<<1
#define R(x) x<<1|1
# define eps 1e-5
# define mod 10007
//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂
using namespace std;

struct node {
    int r,l,mid;
    int lazy1,lazy2;
    int sum[4];
} tr[4*MAX];
int n,m;

void up(int num) {
    for(int i=1; i<=3; i++) tr[num].sum[i] = (tr[L(num)].sum[i] + tr[R(num)].sum[i]) % mod;
}

int cal2(int x) {
    return x * x % mod;
}

int cal3(int x) {
    return cal2(x) * x % mod;
}

void build(int l,int r,int num) {
    tr[num].l = l;
    tr[num].r = r;
    tr[num].mid = (l+r) >> 1;
    tr[num].lazy1 = 0;
    tr[num].lazy2 = 1;
    if(l == r) {
        for(int i=1; i<=3; i++) tr[num].sum[i] = 0;
        return ;
    }
    build(l,tr[num].mid,L(num));
    build(tr[num].mid+1,r,R(num));
    up(num);
    //
}

void down(int num) {
    if(tr[num].lazy2 != 1) {
        tr[L(num)].lazy2 = tr[L(num)].lazy2 * tr[num].lazy2 % mod;
        tr[L(num)].lazy1 = tr[L(num)].lazy1 * tr[num].lazy2 % mod;
        tr[R(num)].lazy2 = tr[R(num)].lazy2 * tr[num].lazy2 % mod;
        tr[R(num)].lazy1 = tr[R(num)].lazy1 * tr[num].lazy2 % mod;

        tr[L(num)].sum[1] = tr[L(num)].sum[1] * tr[num].lazy2 % mod;
        tr[R(num)].sum[1] = tr[R(num)].sum[1] * tr[num].lazy2 % mod;

        tr[L(num)].sum[2] = tr[L(num)].sum[2] * cal2(tr[num].lazy2) % mod;
        tr[R(num)].sum[2] = tr[R(num)].sum[2] * cal2(tr[num].lazy2) % mod;

        tr[L(num)].sum[3] = tr[L(num)].sum[3] * cal3(tr[num].lazy2) % mod;
        tr[R(num)].sum[3] = tr[R(num)].sum[3] * cal3(tr[num].lazy2) % mod;
        tr[num].lazy2 = 1;
    }
    if(tr[num].lazy1 != 0) {
        tr[L(num)].lazy1 = tr[L(num)].lazy1 + tr[num].lazy1 % mod;
        tr[R(num)].lazy1 = tr[R(num)].lazy1 + tr[num].lazy1 % mod;
        int lenl = tr[L(num)].r - tr[L(num)].l + 1;
        int lenr = tr[R(num)].r - tr[R(num)].l + 1;
        tr[L(num)].sum[3] = (tr[L(num)].sum[3] + cal3(tr[num].lazy1) * lenl % mod) % mod;
        tr[R(num)].sum[3] = (tr[R(num)].sum[3] + cal3(tr[num].lazy1) * lenr % mod) % mod;
        tr[L(num)].sum[3] = (tr[L(num)].sum[3] + 3 * tr[L(num)].sum[1] % mod * cal2(tr[num].lazy1) % mod) % mod;
        tr[R(num)].sum[3] = (tr[R(num)].sum[3] + 3 * tr[R(num)].sum[1] % mod * cal2(tr[num].lazy1) % mod) % mod;
        tr[L(num)].sum[3] = (tr[L(num)].sum[3] + 3 * tr[L(num)].sum[2] % mod * tr[num].lazy1 % mod) % mod;
        tr[R(num)].sum[3] = (tr[R(num)].sum[3] + 3 * tr[R(num)].sum[2] % mod * tr[num].lazy1 % mod) % mod;

        tr[L(num)].sum[2] = (tr[L(num)].sum[2] + cal2(tr[num].lazy1) * lenl % mod) % mod;
        tr[R(num)].sum[2] = (tr[R(num)].sum[2] + cal2(tr[num].lazy1) * lenr % mod) % mod;
        tr[L(num)].sum[2] = (tr[L(num)].sum[2] + 2 * tr[L(num)].sum[1] % mod * tr[num].lazy1 % mod) % mod;
        tr[R(num)].sum[2] = (tr[R(num)].sum[2] + 2 * tr[R(num)].sum[1] % mod * tr[num].lazy1 % mod) % mod;

        tr[L(num)].sum[1] = (tr[L(num)].sum[1] + tr[num].lazy1 * lenl % mod) % mod;
        tr[R(num)].sum[1] = (tr[R(num)].sum[1] + tr[num].lazy1 * lenr % mod) % mod;

        tr[num].lazy1 = 0;
    }
}

void update(int l,int r,int num,int k1,int k2) {
    if(l == tr[num].l && r == tr[num].r) {
        if(k2 != 1) {
            tr[num].lazy2 = tr[num].lazy2 * k2 % mod;
            tr[num].lazy1 = k2 * tr[num].lazy1 % mod;
            tr[num].sum[3] = tr[num].sum[3] * cal3(k2) % mod;
            tr[num].sum[2] = tr[num].sum[2] * cal2(k2) % mod;
            tr[num].sum[1] = tr[num].sum[1] * k2 % mod;
        }
        if(k1 != 0) {
            int len = tr[num].r - tr[num].l + 1;
            tr[num].lazy1 = k1 + tr[num].lazy1 % mod;
            tr[num].sum[3] = (tr[num].sum[3] + cal3(k1) * len % mod) % mod;
            tr[num].sum[3] = (tr[num].sum[3] + 3 * tr[num].sum[1] % mod * cal2(k1) % mod) % mod;
            tr[num].sum[3] = (tr[num].sum[3] + 3 * tr[num].sum[2] % mod * k1 % mod) % mod;

            tr[num].sum[2] = (tr[num].sum[2] + cal2(k1) * len % mod) % mod;
            tr[num].sum[2] = (tr[num].sum[2] + 2 * tr[num].sum[1] % mod * k1 % mod) % mod;

            tr[num].sum[1] = (tr[num].sum[1] + k1 * len % mod) % mod;
        }
        return ;
    }
    down(num);
    if(r <= tr[num].mid) {
        update(l,r,L(num),k1,k2);
    } else if(l > tr[num].mid) {
        update(l,r,R(num),k1,k2);
    } else {
        update(l,tr[num].mid,L(num),k1,k2);
        update(tr[num].mid + 1,r,R(num),k1,k2);
    }
    up(num);
}

int query(int l,int r,int num,int p) {
    if(l == tr[num].l && r == tr[num].r) {
        return tr[num].sum[p] % mod;
    }
    down(num);
    if(r <= tr[num].mid) {
        return query(l,r,L(num), p);
    } else if(l > tr[num].mid) {
        return query(l,r,R(num), p);
    } else {
        return (query(l,tr[num].mid,L(num),p) + query(tr[num].mid + 1,r,R(num),p)) % mod;
    }
}

void test(int n) {
    for(int i=1; i<=3*n; i++) {
        printf("l:%d r:%d sum:%d lazy1:%d lazy2:%d\n",tr[i].l,tr[i].r,tr[i].sum[3],tr[i].lazy1,tr[i].lazy2);
    }
}
int main() {
    int x,y,c,p;
    while(cin >> n >> m) {
        if(n == 0 && m == 0) break;
        build(1,n,1);
        for(int i=0; i<m; i++) {
            scanf("%d%d%d%d",&p,&x,&y,&c);
            if(p == 1) {
                update(x,y,1,c,1);
            }
            if(p == 2) {
                update(x,y,1,0,c);
            }
            if(p == 3) {
                update(x,y,1,c,0);
            }
            if(p == 4) {
                printf("%d\n",query(x,y,1,c));
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值