HDU4578 - Transformation (线段树)

Description

思路

加、乘、设值是常规操作,主要难点是解决p次方的求和操作。这里用sum数组分别存储1到3次方的求和结果。因为对2次方求和的操作需要1次方求和,对3次方求和的操作需要2次方求和。因此维护好三个值就可以直接套板子。

线段树区间操作有多种操作时,要注意操作的优先级。在pushdown中,优先级高的操作要优先处理。这里显然优先级设值>乘>加,所以在pushdown中,设值优先对子节点的信息进行更新;其次是乘,加。在更新优先级高的lazy时,也要更新所有优先级比它低的lazy,不要漏了高优先级对低优先级的影响。

pushdown的功能是传递lazy标记和更新子节点信息,所以在叶子结点的时候不能pushdown。
为了防止出错,在update中,当找到一个完全覆盖的区间时,由于这个区间可能是叶子结点,所以不应该在这里更新lazy以后pushdown,而是直接更新sum的值和lazy。更新sum值得操作和pushdown更新子节点sum值得操作是一模一样的,所以可以通过检测update和pushdown是否相同判断是否代码写错了。(这题我pushdown忘记更新低优先级的lazy,我是在和update对比以后发现这个错误)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <queue>


using namespace std;
#define endl '\n'
typedef long long ll;

const int N = 100000 + 100;
const int M = 10007;

int lazy[N << 2][3];
int sum[N << 2][3];

void pushup(int rt) {
    for(int i = 0; i < 3; i++)
        sum[rt][i] = (sum[rt << 1][i] + sum[rt << 1 | 1][i]) % M;
}

void add(int rt, int len, int val) {
    int a1 = val;
    int a2 = (a1 * a1) % M;
    int a3 = (a2 * a1) % M;
    sum[rt][2] = (sum[rt][2] + 3 * a1 * sum[rt][1] % M + 3 * a2 * sum[rt][0] % M + len * a3 % M) % M;
    sum[rt][1] = (sum[rt][1] + 2 * sum[rt][0] * a1 + len * a2) % M;
    sum[rt][0] = (sum[rt][0] + len * a1) % M;
    
}

void mul(int rt, int val) {
    int m = val % M;
    for(int i = 0; i < 3; i++) {
        sum[rt][i] = (sum[rt][i] * m) % M;
        m = (m * val) % M;
    }
}

void change(int rt, int len, int val) {
    int c = val;
    for(int i = 0; i < 3; i++) {
        sum[rt][i] = c * len % M;
        c = c * val % M;
    }
}
void pd1(int rt, int llen, int rlen, int val) {
    add(rt << 1, llen, val);
    add(rt << 1 | 1, rlen, val);
}
void pd2(int rt, int llen, int rlen, int val) {
    mul(rt << 1, val);
    mul(rt << 1 | 1, val);
}

void pd3(int rt, int llen, int rlen, int val) {
    change(rt << 1, llen,val);
    change(rt << 1 | 1, rlen, val);
}


void pushdown(int rt, int l, int r) { // type : 1 加 2 乘 3 变
    int len = r - l + 1;
    int llen = (len + 1) >> 1;
    int rlen = len >> 1;
    if(lazy[rt][2]) {
        pd3(rt, llen, rlen, lazy[rt][2]);
        lazy[rt << 1][2] = lazy[rt][2] % M;
        lazy[rt << 1 | 1][2] = lazy[rt][2] % M;

        lazy[rt << 1][1] = 1;
        lazy[rt << 1 | 1][1] = 1;
        lazy[rt << 1][0] = 0;
        lazy[rt << 1 | 1][0] = 0;
    }
    if(lazy[rt][1] > 1) {
        pd2(rt, llen, rlen, lazy[rt][1]);
        lazy[rt << 1][1] *= lazy[rt][1];
        lazy[rt << 1][1] %= M;
        lazy[rt << 1 | 1][1] *= lazy[rt][1];
        lazy[rt << 1 | 1][1] %= M;

        lazy[rt << 1][0] *= lazy[rt][1];
        lazy[rt << 1][0] %= M;
        lazy[rt << 1 | 1][0] *= lazy[rt][1];
        lazy[rt << 1 | 1][0] %= M;
    }
    if(lazy[rt][0]) {
        pd1(rt, llen, rlen, lazy[rt][0]);
        lazy[rt << 1][0] += lazy[rt][0];
        lazy[rt << 1][0] %= M;
        lazy[rt << 1 | 1][0] += lazy[rt][0];
        lazy[rt << 1 | 1][0] %= M;
    }
    
    lazy[rt][2] = 0;
    lazy[rt][1] = 1;
    lazy[rt][0] = 0;
}



void build(int l, int r, int rt) {
    if(l == r) {
        lazy[rt][0] = lazy[rt][2] = 0;
        lazy[rt][1] = 1;
        sum[rt][0] = sum[rt][1] = sum[rt][2] = 0;
    } else {
        lazy[rt][0] = lazy[rt][2] = 0;
        lazy[rt][1] = 1;
        int mid = (l + r) / 2;
        build(l, mid, rt << 1);
        build(mid + 1, r, rt << 1 | 1);
        pushup(rt);
    }
}

void update(int l, int r, int L, int R,int val, int rt, int type) {
    if(L <= l && R >= r) {
        if(type == 1) {
            add(rt, r - l + 1, val);
            lazy[rt][0] = lazy[rt][0] + val % M;
        } else if(type == 2) {
            mul(rt, val);
            lazy[rt][1] = lazy[rt][1] * val % M;
            lazy[rt][0] = lazy[rt][0] * val % M;
        } else {
            change(rt, r - l + 1, val);
            lazy[rt][2] = val % M;
            lazy[rt][1] = 1;
            lazy[rt][0] = 0;
        }
    } else {
        pushdown(rt, l, r);
        int mid = (l + r) / 2;
        if(L <= mid) update(l, mid, L , R, val, rt << 1, type);
        if(mid < R) update(mid + 1, r, L ,R, val, rt << 1 | 1, type);
        pushup(rt);
    }
}


int query_sum(int l, int r, int L, int R, int rt, int p) {
    if(L <= l && R >= r) {
        return sum[rt][p - 1];
    } else {
        int res = 0;
        int mid = (l +r) / 2;
        pushdown(rt, l, r);
        if(L <= mid) res += query_sum(l, mid, L, R, rt << 1, p);
        if(mid < R) res += query_sum(mid + 1, r, L, R, rt << 1 | 1, p);
        pushup(rt); 
        res %= M;
        return res;
    }
}

int main() {
    ios::sync_with_stdio(false);
    int t;
    int n, m;
    while(cin >> n >> m) {
        if(n == 0 && m == 0) break;
        build(1, n, 1);
        while(m--) {
            int k, l, r, val;
            cin >> k >> l >> r >> val;
            if(k < 4) update(1, n, l, r, val, 1, k);
            else cout << query_sum(1, n, l, r, 1, val) << endl;
        }
    }
}
posted @ 2020-04-23 13:34  limil  阅读(197)  评论(0编辑  收藏  举报