线段树刷题记录

一篇讲解很好的线段树博客:数据结构--线段树篇_数据结构线段树-CSDN博客

一、区间查询 无修改:

(一)最值问题:

1.P1816 忠诚 - 洛谷
思路:

模板。

注意:

无。

代码:
cpp 复制代码
#include <bits/stdc++.h>

#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;

const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = 1 << 31;
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;

template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cout << a[i] << ' ';
    return os;
}

template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cin >> a[i];
    return in;
}

/* ----------------- 有乘就强转,前缀和开ll ----------------- */

int v[N];
struct Node
{
    int l, r;
    int minn;
} tr[N * 4];

void pushup(int u)
{
    tr[u].minn = min(tr[u << 1].minn, tr[u << 1 | 1].minn);
}

void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = {l, r, v[l]};
        return;
    }

    tr[u] = {l, r};
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

int query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        return tr[u].minn;
    }

    int mid = tr[u].l + tr[u].r >> 1;
    int minn = MAX;
    if (l <= mid)
        minn = min(minn, query(u << 1, l, r));
    if (r > mid)
        minn = min(minn, query(u << 1 | 1, l, r));
    return minn;
}

void solve()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> v[i];

    build(1, 1, n);

    while (m--)
    {
        int l, r;
        cin >> l >> r;
        cout << query(1, l, r) << ' ';
    }
    cout << endl;
}

int main()
{
    ioscc;

    solve();

    return 0;
}
2.P1886 滑动窗口 /【模板】单调队列 - 洛谷
思路:

模板。

注意:

无。

代码:
cpp 复制代码
#include <bits/stdc++.h>

#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;

const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = 1 << 31;
const int MOD = 1e9 + 7;
const int N = 1e6 + 10;

template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cout << a[i] << ' ';
    return os;
}

template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cin >> a[i];
    return in;
}

/* ----------------- 有乘就强转,前缀和开ll ----------------- */

int v[N];
struct Node
{
    int l, r;
    int minn, maxx;
} tr[N * 4];

void pushup(int u)
{
    tr[u].minn = min(tr[u << 1].minn, tr[u << 1 | 1].minn);
    tr[u].maxx = max(tr[u << 1].maxx, tr[u << 1 | 1].maxx);
}

void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = {l, r, v[l], v[l]};
        return;
    }

    tr[u] = {l, r, 0, 0};
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

int queryMin(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        return tr[u].minn;
    }

    int mid = tr[u].l + tr[u].r >> 1;
    int minn = MAX;
    if (l <= mid)
        minn = min(minn, queryMin(u << 1, l, r));
    if (r > mid)
        minn = min(minn, queryMin(u << 1 | 1, l, r));
    return minn;
}

int queryMax(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        return tr[u].maxx;
    }

    int mid = tr[u].l + tr[u].r >> 1;
    int maxx = MIN;
    if (l <= mid)
        maxx = max(maxx, queryMax(u << 1, l, r));
    if (r > mid)
        maxx = max(maxx, queryMax(u << 1 | 1, l, r));
    return maxx;
}

void solve()
{
    int n, k;
    cin >> n >> k;

    for (int i = 1; i <= n; ++i)
        cin >> v[i];

    build(1, 1, n);

    for (int i = 1; i <= n - k + 1; ++i)
        cout << queryMin(1, i, i + k - 1) << ' ';
    cout << endl;
    for (int i = 1; i <= n - k + 1; ++i)
        cout << queryMax(1, i, i + k - 1) << ' ';
    cout << endl;
}

int main()
{
    ioscc;

    solve();

    return 0;
}

二、区间查询 单点修改:

(一)区间和问题:

1.P2068 统计和 - 洛谷
思路:

模板。

注意:

无。

代码:
cpp 复制代码
#include <bits/stdc++.h>

#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;

const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = 1 << 31;
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;

template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cout << a[i] << ' ';
    return os;
}

template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cin >> a[i];
    return in;
}

/* ----------------- 有乘就强转,前缀和开ll ----------------- */

struct Node
{
    int l, r;
    ll sum;
} tr[N * 4];

void pushup(int u)
{
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = {l, r, 0};
        return;
    }

    tr[u] = {l, r, 0};
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

ll query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].sum;

    int mid = tr[u].l + tr[u].r >> 1;
    ll sum = 0;
    if (l <= mid)
        sum += query(u << 1, l, r);
    if (r > mid)
        sum += query(u << 1 | 1, l, r);
    return sum;
}

void update(int u, int x, int v)
{
    if (tr[u].l == x && tr[u].r == x)
        tr[u].sum += v;
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid)
            update(u << 1, x, v);
        else
            update(u << 1 | 1, x, v);
        pushup(u);
    }
}

void solve()
{
    int n, m;
    cin >> n >> m;

    build(1, 1, n);
    while (m--)
    {
        char op;
        int a, b;
        cin >> op >> a >> b;
        if (op == 'x')
            update(1, a, b);
        else
            cout << query(1, a, b) << endl;
    }
}

int main()
{
    ioscc;

    solve();

    return 0;
}
2.P2184 贪婪大陆 - 洛谷
思路:

区间修改时使用一种类差分的思想,每次埋地雷的时候只在区间左右端点累加一次值,这样就将问题装换为了单点修改;查询时我们再使用前缀和思想统计区间 [l, r] 区间内的地雷数。具体实现就是使用线段树维护两个sum,既区间左端点的地雷和区间右端点的地雷;在查询区间 [l ,r] 时,就可以用 [1, r] 的起点数减去 [1, l] 的终点数。

注意:

无。

代码:
cpp 复制代码
#include <bits/stdc++.h>

#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
#define ls u << 1
#define rs u << 1 | 1
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;

const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = 1 << 31;
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;

template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cout << a[i] << ' ';
    return os;
}

template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cin >> a[i];
    return in;
}

/* ----------------- 有乘就强转,前缀和开ll ----------------- */

struct Node
{
    int l, r;
    int sum[2];
} tr[N * 4];

void pushup(int u, int k)
{
    tr[u].sum[k] = tr[u << 1].sum[k] + tr[u << 1 | 1].sum[k];
}

void build(int u, int l, int r)
{
    tr[u] = {l, r, 0, 0};
    if (l == r)
        return;
    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
}

ll query(int u, int l, int r, int k)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].sum[k];

    int mid = tr[u].l + tr[u].r >> 1;
    ll sum = 0;
    if (l <= mid)
        sum += query(u << 1, l, r, k);
    if (r > mid)
        sum += query(u << 1 | 1, l, r, k);
    return sum;
}

void update(int u, int x, int k)
{
    if (tr[u].l == tr[u].r)
    {
        ++tr[u].sum[k];
        return;
    }

    int mid = tr[u].l + tr[u].r >> 1;
    if (x <= mid)
        update(u << 1, x, k);
    else
        update(u << 1 | 1, x, k);
    pushup(u, k);
}

void solve()
{
    int n, m;
    cin >> n >> m;

    build(1, 1, n);

    while (m--)
    {
        int op, l, r;
        cin >> op >> l >> r;

        if (op == 1)
            update(1, l, 0), update(1, r, 1);
        else
            cout << query(1, 1, r, 0) - query(1, 1, l - 1, 1) << endl;
    }
}

int main()
{
    ioscc;

    solve();

    return 0;
}

(二)最值问题

1.P1198 [JSOI2008] 最大数 - 洛谷
思路:

模板。

注意:

虽然线段树初始为空的,也要初始化 m 个位置为后续做准备。

代码:
cpp 复制代码
#include <bits/stdc++.h>

#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;

const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = -2e18;
const int MOD = 1e9 + 7;
const int N = 2e5 + 10;

template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cout << a[i] << ' ';
    return os;
}

template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cin >> a[i];
    return in;
}

/* ----------------- 有乘就强转,前缀和开ll ----------------- */

struct Node
{
    int l, r;
    ll maxx;
} tr[N << 2];

void pushup(int u)
{
    tr[u].maxx = max(tr[u << 1].maxx, tr[u << 1 | 1].maxx);
}

void build(int u, int l, int r)
{
    tr[u] = {l, r, 0};

    if (l == r)
        return;

    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
}

ll query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].maxx;

    int mid = tr[u].l + tr[u].r >> 1;
    ll maxx = MIN;
    if (l <= mid)
        maxx = max(maxx, query(u << 1, l, r));
    if (r > mid)
        maxx = max(maxx, query(u << 1 | 1, l, r));
    return maxx;
}

void update(int u, int x, int v)
{
    if (tr[u].l == tr[u].r)
    {
        tr[u].maxx = v;
        return;
    }

    int mid = tr[u].l + tr[u].r >> 1;
    if (x <= mid)
        update(u << 1, x, v);
    else
        update(u << 1 | 1, x, v);
    pushup(u);
}

void solve()
{
    ll n = 0, m;
    int mod;
    cin >> m >> mod;

    build(1, 1, m);

    int last = 0;
    while (m--)
    {
        char op;
        int x;
        cin >> op >> x;
        if (op == 'Q')
        {
            last = query(1, n - x + 1, n);
            cout << last << endl;
        }
        else
        {
            ++n;
            int ans = ((ll)x + last) % mod;
            update(1, n, ans);
        }
    }
}

int main()
{
    ioscc;

    solve();

    return 0;
}

三、区间查询 区间修改:

(一)区间和问题:

1.P2357 守墓人 - 洛谷
思路:

模板。

注意:

开ll。

代码:
cpp 复制代码
#include <bits/stdc++.h>

#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;

const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = 1 << 31;
const int MOD = 1e9 + 7;
const int N = 2e5 + 10;

template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cout << a[i] << ' ';
    return os;
}

template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cin >> a[i];
    return in;
}

/* ----------------- 有乘就强转,前缀和开ll ----------------- */

ll v[N];
struct Node
{
    int l, r;
    ll sum;
    ll add;
} tr[N * 4];

void pushup(int u)
{
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void pushdown(int u)
{
    if (tr[u].add)
    {
        tr[u << 1].sum += tr[u].add * (tr[u << 1].r - tr[u << 1].l + 1);
        tr[u << 1 | 1].sum += tr[u].add * (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1);
        tr[u << 1].add += tr[u].add;
        tr[u << 1 | 1].add += tr[u].add;
        tr[u].add = 0;
    }
}

void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = {l, r, v[l], 0};
        return;
    }

    tr[u] = {l, r, 0, 0};
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

ll query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].sum;

    pushdown(u);

    int mid = tr[u].l + tr[u].r >> 1;
    ll sum = 0;
    if (l <= mid)
        sum += query(u << 1, l, r);
    if (r > mid)
        sum += query(u << 1 | 1, l, r);
    return sum;
}

void update(int u, int l, int r, int v)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].sum += (ll)(tr[u].r - tr[u].l + 1) * v;
        tr[u].add += v;
        return;
    }

    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid)
        update(u << 1, l, r, v);
    if (r > mid)
        update(u << 1 | 1, l, r, v);
    pushup(u);
}

void solve()
{
    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; ++i)
        cin >> v[i];

    build(1, 1, n);
    while (m--)
    {
        int op;
        int l, r, v;
        cin >> op;
        if (op == 1)
        {
            cin >> l >> r >> v;
            update(1, l, r, v);
        }
        else if (op == 2)
        {
            cin >> v;
            update(1, 1, 1, v);
        }
        else if (op == 3)
        {
            cin >> v;
            update(1, 1, 1, -v);
        }
        else if (op == 4)
        {
            cin >> l >> r;
            cout << query(1, l, r) << endl;
        }
        else
            cout << query(1, 1, 1) << endl;
    }
}

int main()
{
    ioscc;

    solve();

    return 0;
}

(二)区间最值+区间和问题:

1.P3130 [USACO15DEC] Counting Haybale P - 洛谷
思路:

线段树维护区间、最小值、区间和、懒标记。

注意:

更新懒标记时也需将节点的最小值加上懒标记的值。

代码:
cpp 复制代码
#include <bits/stdc++.h>

#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;

const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = 1 << 31;
const int MOD = 1e9 + 7;
const int N = 2e5 + 10;

template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cout << a[i] << ' ';
    return os;
}

template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cin >> a[i];
    return in;
}

/* ----------------- 有乘就强转,前缀和开ll ----------------- */

ull v[N];
struct Node
{
    int l, r;
    ull minn;
    ull sum;
    ull add;
} tr[N * 4];

void pushup(int u)
{
    tr[u].minn = min(tr[u << 1].minn, tr[u << 1 | 1].minn);
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void pushdown(int u)
{
    if (tr[u].add)
    {
        tr[u << 1].sum += tr[u].add * (tr[u << 1].r - tr[u << 1].l + 1);
        tr[u << 1 | 1].sum += tr[u].add * (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1);
        tr[u << 1].minn += tr[u].add;
        tr[u << 1 | 1].minn += tr[u].add;
        tr[u << 1].add += tr[u].add;
        tr[u << 1 | 1].add += tr[u].add;
        tr[u].add = 0;
    }
}

void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = {l, r, v[l], v[l], 0};
        return;
    }

    tr[u] = {l, r, 0, 0, 0};
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

ull querySum(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        return tr[u].sum;
    }

    pushdown(u);

    int mid = tr[u].l + tr[u].r >> 1;
    ull sum = 0;
    if (l <= mid)
        sum += querySum(u << 1, l, r);
    if (r > mid)
        sum += querySum(u << 1 | 1, l, r);
    return sum;
}

ull queryMin(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        return tr[u].minn;
    }

    pushdown(u);

    int mid = tr[u].l + tr[u].r >> 1;
    ull minn = MAX;
    if (l <= mid)
        minn = min(minn, queryMin(u << 1, l, r));
    if (r > mid)
        minn = min(minn, queryMin(u << 1 | 1, l, r));
    return minn;
}

void update(int u, int l, int r, int v)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].sum += (ull)(tr[u].r - tr[u].l + 1) * v;
        tr[u].minn += v;
        tr[u].add += v;
        return;
    }

    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid)
        update(u << 1, l, r, v);
    if (r > mid)
        update(u << 1 | 1, l, r, v);
    pushup(u);
}

void solve()
{
    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; ++i)
        cin >> v[i];

    build(1, 1, n);

    while (m--)
    {
        char op;
        int a, b, c;
        cin >> op;
        if (op == 'M')
        {
            cin >> a >> b;
            cout << queryMin(1, a, b) << endl;
        }
        else if (op == 'P')
        {
            cin >> a >> b >> c;
            update(1, a, b, c);
        }
        else
        {
            cin >> a >> b;
            cout << querySum(1, a, b) << endl;
        }
    }
}

int main()
{
    ioscc;

    solve();

    return 0;
}

(三)区间和+区间乘

1.P3373 【模板】线段树 2 - 洛谷
思路:

维护乘和加两个懒标记,由于乘法优先级高于加法,所以当前节点的值为 sum * mul + add,

当父节点下传懒标记时,设 m,a 为父节点下传的乘法与加法懒标记,所以当前节点值为 (sum *

mul + add) * m + a,可得 sum * mul * m + add * m + a,所以mul和sum的更新值为 mul = mul

* madd = add * m + a

注意:

开ll,乘和加的优先级。

代码:
cpp 复制代码
#include <bits/stdc++.h>

#define ioscc ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
#define me(a, x) memset(a, x, sizeof a)
#define all(a) a.begin(), a.end()
#define sz(a) ((int)(a).size())
#define pb(a) push_back(a)
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<vector<int>> vvi;
typedef vector<int> vi;
typedef vector<bool> vb;

const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, 1, 0, -1};
const int MAX = (1ll << 31) - 1;
const int MIN = 1 << 31;
const int MOD = 1e9 + 7;
const int N = 1e5 + 10;

template <class T>
ostream &operator<<(ostream &os, const vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cout << a[i] << ' ';
    return os;
}

template <class T>
istream &operator>>(istream &in, vector<T> &a) noexcept
{
    for (int i = 0; i < sz(a) - 10; i++)
        std::cin >> a[i];
    return in;
}

/* ----------------- 有乘就强转,前缀和开ll ----------------- */

int mod;
ll v[N];
struct Node
{
    int l, r;
    ll sum;
    ll add, mul;
} tr[N << 2];

void pushup(int u)
{
    tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum) % mod;
}

void calc(Node &t, ll m, ll a)
{
    t.sum = (t.sum * m % mod + (t.r - t.l + 1) * a % mod) % mod;
    t.mul = t.mul * m % mod;
    t.add = (t.add * m + a) % mod;
}

void pushdown(int u)
{
    calc(tr[u << 1], tr[u].mul, tr[u].add);
    calc(tr[u << 1 | 1], tr[u].mul, tr[u].add);
    tr[u].add = 0;
    tr[u].mul = 1;
}

void build(int u, int l, int r)
{
    if (l == r)
    {
        tr[u] = {l, r, v[l], 0, 1};
        return;
    }

    tr[u] = {l, r, 0, 0, 1};
    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

ll query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        return tr[u].sum % mod;
    }

    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    ll sum = 0;
    if (l <= mid)
        sum += query(u << 1, l, r) % mod;
    if (r > mid)
        sum += query(u << 1 | 1, l, r) % mod;
    return sum % mod;
}

void update(int u, int l, int r, int m, int a)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        calc(tr[u], m, a);
        return;
    }

    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid)
        update(u << 1, l, r, m, a);
    if (r > mid)
        update(u << 1 | 1, l, r, m, a);
    pushup(u);
}

void solve()
{
    int n, m;
    cin >> n >> m >> mod;

    for (int i = 1; i <= n; ++i)
        cin >> v[i];

    build(1, 1, n);

    while (m--)
    {
        int op;
        int x, y, v;
        cin >> op >> x >> y;
        if (op == 1)
        {
            cin >> v;
            update(1, x, y, v, 0);
        }
        else if (op == 2)
        {
            cin >> v;
            update(1, x, y, 1, v);
        }
        else
            cout << query(1, x, y) % mod << endl;
    }
}

int main()
{
    ioscc;

    solve();

    return 0;
}
相关推荐
Y1nhl10 分钟前
力扣_链表_python版本
开发语言·python·算法·leetcode·链表·职场和发展
qq_4017004126 分钟前
C语言中位运算以及获取低8位和高8位、高低位合并
c语言·开发语言·算法
CoovallyAIHub29 分钟前
YOLO模型优化全攻略:从“准”到“快”,全靠这些招!
深度学习·算法·计算机视觉
闻缺陷则喜何志丹34 分钟前
【BFS】 P10864 [HBCPC2024] Genshin Impact Startup Forbidden II|普及+
c++·算法·宽度优先·洛谷
MicroTech20251 小时前
微算法科技(NASDAQ: MLGO)探索Grover量子搜索算法,利用量子叠加和干涉原理,实现在无序数据库中快速定位目标信息的效果。
数据库·科技·算法
qianbo_insist1 小时前
c++ python 共享内存
开发语言·c++·python
今天背单词了吗9801 小时前
算法学习笔记:8.Bellman-Ford 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·开发语言·后端·算法·最短路径问题
手握风云-1 小时前
优选算法的链脉之韵:链表专题
数据结构·算法·链表
Coding小公仔2 小时前
LeetCode 151. 反转字符串中的单词
开发语言·c++·算法