社区讨论

有没有大佬帮帮孩子看看代码吧

P3373【模板】线段树 2参与者 1已保存回复 0

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
0 条
当前快照
1 份
快照标识符
@ltpp3fc6
此快照首次捕获于
2024/03/13 19:05
2 年前
此快照最后确认于
2024/03/13 20:57
2 年前
查看原帖
CPP
#include<iostream>
#define ll long long 
#define N 100005
using namespace std;

int n, q, m;
ll a[N]; // 存储原始数组

struct node
{
    int l, r, flag, tag, vis; // 区间左右端点、标记变量、标记值、操作类型
    ll sum; // 区间和
} tree[N*4]; // 线段树节点

// 构建线段树
void build(int i, int l, int r)
{
    tree[i].l = l;
    tree[i].r = r;
    tree[i].tag = 0; // 区间乘法标记初始化为0
    tree[i].flag = 1; // 区间加法标记初始化为1
    tree[i].vis = 0; // 节点标记初始化为0
    
    if (l == r)
    {
        tree[i].sum = a[i]; // 叶节点的值为原始数组的值
        return;
    }
    
    int m = (l + r) / 2;
    build(i * 2, l, m); // 递归构建左子树
    build(i * 2 + 1, m + 1, r); // 递归构建右子树
    tree[i].sum = tree[i * 2].sum + tree[i * 2 + 1].sum; // 更新当前节点的区间和
}

// 下传加法标记
void down1(int i)
{
    // 更新左子节点的加法标记和区间和
    tree[i * 2].tag = (tree[i * 2].tag + tree[i].tag) % m;
    tree[i * 2].sum = (tree[i * 2].sum + (tree[i * 2].r - tree[i * 2].l + 1) * tree[i].tag) % m;
    
    // 更新右子节点的加法标记和区间和
    tree[i * 2 + 1].tag = (tree[i * 2 + 1].tag + tree[i].tag) % m;
    tree[i * 2 + 1].sum = (tree[i * 2 + 1].sum + (tree[i * 2 + 1].r - tree[i * 2 + 1].l + 1) * tree[i].tag) % m;
    
    tree[i].tag = 0; // 当前节点的加法标记清零
    
    // 更新当前节点的操作类型
    if (tree[i].flag > 1)
        tree[i].vis = 2;
    else
        tree[i].vis = 0;
    
    // 更新子节点的操作类型
    if (tree[i * 2].vis == 0)
        tree[i * 2].vis = 1;
    
    if (tree[i * 2 + 1].vis == 0)
        tree[i * 2 + 1].vis = 1;
}

// 下传乘法标记
void down2(int i)
{
    // 更新左子节点的乘法标记和区间和
    tree[i * 2].flag = (tree[i * 2].flag * tree[i].flag) % m;
    tree[i * 2].sum = (tree[i * 2].sum * tree[i].flag) % m;
    
    // 更新右子节点的乘法标记和区间和
    tree[i * 2 + 1].flag = (tree[i * 2 + 1].flag * tree[i].flag) % m;
    tree[i * 2 + 1].sum = (tree[i * 2 + 1].sum * tree[i].flag) % m;
    
    tree[i].flag = 1; // 当前节点的乘法标记重置为1
    
    // 更新当前节点的操作类型
    if (tree[i].tag > 1)
        tree[i].vis = 1;
    else
        tree[i].vis = 0;
    
    // 更新子节点的操作类型
    if (tree[i * 2].vis == 0)
        tree[i * 2].vis = 2;
    
    if (tree[i * 2 + 1].vis == 0)
        tree[i * 2 + 1].vis = 2;
}

// 更新操作1(区间加法)
void update1(int i, int l, int r, int k)
{
    if ((tree[i].r < l) || (tree[i].l > r))
        return;
    
    if ((tree[i].l >= 1) && (tree[i].r <= r))
    {
        // 更新当前节点的加法标记和区间和
        if (tree[i].vis == 0)
            tree[i].vis = 1;
        
        tree[i].tag = (tree[i].tag + k) % m;
        tree[i].sum = (tree[i].sum + (tree[i].r - tree[i].l + 1) * k) % m;
        return;
    }
    
    // 下传标记
    if (tree[i].flag > 1 && tree[i].tag > 0)
    {
        if (tree[i].vis == 1)
        {
            down1(i);
            down2(i);
        }
        else
        {
            down2(i);
            down1(i);
        }
    }
    else if (tree[i].tag > 0)
        down1(i);
    else if (tree[i].flag > 1)
        down2(i);
    
    // 递归更新左右子节点
    update1(i * 2, l, r, k);
    update1(i * 2 + 1, l, r, k);
    tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % m; // 更新当前节点的区间和
}

// 更新操作2(区间乘法)
void update2(int i, int l, int r, int k)
{
    if ((tree[i].r < l) || (tree[i].l > r))
        return;
    
    if ((tree[i].l >= 1) && (tree[i].r <= r))
    {
        // 更新当前节点的乘法标记和区间和
        if (tree[i].vis == 0)
            tree[i].vis = 2;
        
        tree[i].tag = (tree[i].tag * k) % m;
        tree[i].sum = (tree[i].sum * k) % m;
        return;
    }
    
    // 下传标记
    if (tree[i].flag > 1 && tree[i].tag > 0)
    {
        if (tree[i].vis == 1)
        {
            down1(i);
            down2(i);
        }
        else
        {
            down2(i);
            down1(i);
        }
    }
    else if (tree[i].tag > 0)
        down1(i);
    else if (tree[i].flag > 1)
        down2(i);
    
    // 递归更新左右子节点
    update2(i * 2, l, r, k);
    update2(i * 2 + 1, l, r, k);
    tree[i].sum = (tree[i * 2].sum + tree[i * 2 + 1].sum) % m; // 更新当前节点的区间和
}

// 查询操作
ll query(int i, int l, int r)
{
    if ((tree[i].r < l) || (tree[i].l > r))
        return 0;
    
    if ((tree[i].l >= 1) && (tree[i].r <= r))
        return tree[i].sum;
    
    // 下传标记
    if (tree[i].flag > 1 && tree[i].tag > 0)
    {
        if (tree[i].vis == 1)
        {
            down1(i);
            down2(i);
        }
        else
        {
            down2(i);
            down1(i);
        }
    }
    else if (tree[i].tag > 0)
        down1(i);
    else if (tree[i].flag > 1)
        down2(i);
    
    return (query(i * 2, l, r) + query(i * 2 + 1, l, r)) % m; // 递归查询左右子节点并返回结果
}

int main()
{
    cin >> n >> q >> m;
    
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    
    build(1, 1, n); // 构建线段树
    
    for (int i = 1; i <= q; i++)
    {
        int v;
        int x, y, k;
        cin >> v;
        
        if (v == 1)
        {
            cin >> x >> y >> k;
            update2(1, x, y, k); // 区间乘法更新操作
        }
        else if (v == 2)
        {
            cin >> x >> y >> k;
            update1(1, x, y, k); // 区间加法更新操作
        }
        else
        {
            cin >> x >> y;
            ll ans = query(1, x, y); // 查询操作
            cout << ans << endl;
        }
    }
    
    return 0;
}

回复

0 条回复,欢迎继续交流。

正在加载回复...