暑假训练 2023-7-16 (线段树的有关操作的题目)

补题

题目链接:Transformation
 
所需算法:线段树
 
题目大意:让你对一段区间 [l, r] 进行四种操作,分别是在一段区间中都增加c或者都乘上c,或者是都变为c,或者是求出这段区间的每个数的p次方的和。
 
对于这些操作,我们只要在线段树中维护 6 个信息

struct Node
{
    int l, r;   // 节点的区间长度
    LL d, mul, add, sum1, sum2, sum3;
    // d 表示这段区间是不是有被置为d过,有则为该值d,无则为0
    // mul 表示累计乘的值 add 表示累计加的值
    // sum1 表示区间的每个元素的值是其值的 1 次方,即 a ^ 1。 sum1 为这些值的总和
    // sum2 表示区间的每个元素的值是其值的 2 次方, 即 a ^ 2。 sum2 为这些值的总和
    // sum3 依上述类推。
}tr[N * 4];

 
注意:这里的优先级是 d > mul > add 的,因为整个区间被置为 d 时,那么其 muladd 应分别赋为 10。即一旦被赋值为 d ,我们仔细想想会想到 d 就是优先级更高。
muladd 优先级更高则是因为在式子 y=ka+b 中当乘一个数x时,结果为y=kxa+bx。再加上zy=kxa+bx+z。设B=bx+z,则y=kxa+B。再乘个t,得y=kxta+Bt。这时你发现了乘和加似乎已经分离了,在接下来的pushdown中,我们按照先将k * x * t乘给左右子区间,再将B * t加到左右子区间是合法且易维护的。
 
另一个需要注意的地方是:
sum3在区间加上c的情况可以由公式(s+c)3展开得

(a1+c)3+(a2+c)3+(a3+c)3+...+(an+c)3=sum3+3sum2c+3sum1c2+c3

sum3=a13+a23+a33+...+an3
sum2=a12+a22+a32+...+an2
sum1=a1+a2+a3+...+an
sum2sum1依次类推。
 
sum3在区间乘上c的情况可以由公式(sc)3

(a1c)3+(a2c)3+(a3c)3+...+(anc)3=sum3c3

sum2sum1依此类推。
 
 
代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <deque>
#include <cmath>
#include <string>
#include <set>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };

const int N = 100010, mod = 10007;

int n, m;
int op, x, y, c;

struct Node
{
    int l, r;
    LL d, mul, add, sum1, sum2, sum3;
}tr[N * 4];

void pushup(int u)
{
    tr[u].sum1 = (tr[u * 2].sum1 + tr[u * 2 + 1].sum1) % mod;
    tr[u].sum2 = (tr[u * 2].sum2 + tr[u * 2 + 1].sum2) % mod;
    tr[u].sum3 = (tr[u * 2].sum3 + tr[u * 2 + 1].sum3) % mod;
}

void pushdown(int u)
{
    int l = u * 2, r = u * 2 + 1;
    if (tr[u].d)
    {
        LL d = tr[u].d;
        tr[l].sum3 = (LL)(tr[l].r - tr[l].l + 1) * d * d * d % mod;
        tr[l].sum2 = (LL)(tr[l].r - tr[l].l + 1) * d * d % mod;
        tr[l].sum1 = (LL)(tr[l].r - tr[l].l + 1) * d % mod;

        tr[r].sum3 = (LL)(tr[r].r - tr[r].l + 1) * d * d * d % mod;
        tr[r].sum2 = (LL)(tr[r].r - tr[r].l + 1) * d * d % mod;
        tr[r].sum1 = (LL)(tr[r].r - tr[r].l + 1) * d % mod;

        tr[l].mul = 1, tr[l].add = 0, tr[l].d = d, tr[r].mul = 1, tr[r].add = 0, tr[r].d = d;
    }
    if (tr[u].mul != 1)
    {
        LL x = tr[u].mul;
        tr[l].sum3 = tr[l].sum3 * x * x * x % mod;
        tr[l].sum2 = tr[l].sum2 * x * x % mod;
        tr[l].sum1 = tr[l].sum1 * x % mod;

        tr[r].sum3 = tr[r].sum3 * x * x * x % mod;
        tr[r].sum2 = tr[r].sum2 * x * x % mod;
        tr[r].sum1 = tr[r].sum1 * x % mod;

        tr[l].mul = tr[l].mul * x % mod, tr[l].add = tr[l].add * x % mod;
        tr[r].mul = tr[r].mul * x % mod, tr[r].add = tr[r].add * x % mod;
    }
    if (tr[u].add > 0)
    {
        LL x = tr[u].add;
        tr[l].sum3 = (tr[l].sum3 % mod + 3 * tr[l].sum2 * x % mod + 3 * tr[l].sum1 * x * x % mod + (LL)(tr[l].r - tr[l].l + 1) * x * x * x % mod) % mod;
        tr[l].sum2 = (tr[l].sum2 + 2 * tr[l].sum1 * x + (LL)(tr[l].r - tr[l].l + 1) * x * x) % mod;
        tr[l].sum1 = (tr[l].sum1 + (LL)(tr[l].r - tr[l].l + 1) * x) % mod;

        tr[r].sum3 = (tr[r].sum3 % mod + 3 * tr[r].sum2 * x % mod + 3 * tr[r].sum1 * x * x % mod + (LL)(tr[r].r - tr[r].l + 1) * x * x * x % mod) % mod;
        tr[r].sum2 = (tr[r].sum2 + 2 * tr[r].sum1 * x + (LL)(tr[r].r - tr[r].l + 1) * x * x) % mod;
        tr[r].sum1 = (tr[r].sum1 + (LL)(tr[r].r - tr[r].l + 1) * x) % mod;

        tr[l].add = (tr[l].add + x) % mod, tr[r].add = (tr[r].add + x) % mod;
    }
    tr[u].mul = 1, tr[u].add = 0, tr[u].d = 0;
}

void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = { l, r, 0, 1, 0, 0, 0, 0 };
    }
    else
    {
        int mid = (l + r) >> 1;
        tr[u] = { l, r, 0, 1, 0, 0, 0, 0 };
        build(u * 2, l, mid), build(u * 2 + 1, mid + 1, r);
    }
}

void modify(int u, int l, int r, int c)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        if (op == 1)
        {
            tr[u].sum3 = (tr[u].sum3 % mod + 3 * tr[u].sum2 * c % mod + 3 * tr[u].sum1 * c * c % mod + (LL)(tr[u].r - tr[u].l + 1) * c * c * c % mod) % mod;
            tr[u].sum2 = (tr[u].sum2 + 2 * tr[u].sum1 * c + (LL)(tr[u].r - tr[u].l + 1) * c * c) % mod;
            tr[u].sum1 = (tr[u].sum1 + (LL)(tr[u].r - tr[u].l + 1) * c % mod) % mod;
            tr[u].add = (tr[u].add + c) % mod; 
        }
        else if (op == 2)
        {
            tr[u].sum3 = tr[u].sum3 * c * c * c % mod;
            tr[u].sum2 = tr[u].sum2 * c * c % mod;
            tr[u].sum1 = tr[u].sum1 * c % mod;
            tr[u].mul = tr[u].mul * c % mod;
            tr[u].add = tr[u].add * c % mod;
        }
        else if (op == 3)
        {
            tr[u].sum3 = (LL)(tr[u].r - tr[u].l + 1) * c * c * c % mod;
            tr[u].sum2 = (LL)(tr[u].r - tr[u].l + 1) * c * c % mod;
            tr[u].sum1 = (LL)(tr[u].r - tr[u].l + 1) * c % mod;
            tr[u].d = c, tr[u].add = 0, tr[u].mul = 1;
        }
    }
    else
    {
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        if (l <= mid)modify(u * 2, l, r, c);
        if (r > mid)modify(u * 2 + 1, l, r, c);
        pushup(u);
    }
}

LL query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        if (c == 1)return tr[u].sum1;
        else if (c == 2)return tr[u].sum2;
        else if (c == 3)return tr[u].sum3;
    }
    else
    {
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        LL sum = 0;
        if (l <= mid)sum = query(u * 2, l, r);
        if (r > mid)sum = (sum + query(u * 2 + 1, l, r)) % mod;
        return sum;
    }
}

int main()
{
    while (scanf("%d%d", &n, &m), n | m)
    {
        build(1, 1, n);

        while (m--)
        {
            scanf("%d%d%d%d", &op, &x, &y, &c);
            if (op <= 3)modify(1, x, y, c);
            else printf("%lld\n", query(1, x, y));
        }
    }

    return 0;
}

 
转载请注明链接哦!

posted @   dkdklcx  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示