专题:线段树

最大数

题意:
添加操作:向序列后添加一个数,序列长度变成 n+1;
询问操作:询问这个序列中最后 L 个数中最大的数是多少
强制在线

//
// Created by vv123 on 2022/9/5.
//
#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2e5 + 10;

struct SegmentTree {
    int mx[N << 2];
    SegmentTree() {
        memset(mx, 0, sizeof mx);
    }
#define mid (l+r>>1)
#define ls (u<<1)
#define rs (u<<1|1)
#define ain (s<=l&&r<=t)
#define lin (s<=mid)
#define rin (t>=mid+1)
    void pushup(int u) {
        mx[u] = max(mx[ls], mx[rs]);
    }
    void upd(int pos, int l, int r, int u, int val) {
        //printf("%d %d %d\n", l, r, u);
        if (l == pos && r == pos) { mx[u] = val; return; }
        if (pos <= mid) upd(pos, l, mid, ls, val);
        else upd(pos, mid + 1, r, rs, val);
        pushup(u);
    }
    int ask(int s, int t, int l, int r, int u) {
        if (ain) return mx[u];
        int res = 0;
        if (lin) res = max(res, ask(s, t, l, mid, ls));
        if (rin) res = max(res, ask(s, t, mid + 1, r, rs));
        return res;
    }
} tr;
int m, p;
signed main() {
    ios::sync_with_stdio(false); cin.tie(0);
    cin >> m >> p;
    int lastans = 0, n = 0;
    for (int i = 1; i <= m; i++) {
        string op; int x;
        cin >> op >> x;
        if (op == "A") {
            tr.upd(n + 1, 1, m, 1, (x + lastans) % p);
            n++;
        } else {
            lastans = tr.ask(n - x + 1, n, 1, m, 1);
            cout << lastans << "\n";
        }
    }
    return 0;
}

单点修改,查询区间最大子段和

//
// Created by vv123 on 2022/9/9.
//
#include <bits/stdc++.h>
#define int long long
using namespace std;

const int mod = 998244353;
const int N = 2e6 + 10;
const int inf = 0x3f3f3f3f;

int n, m, a[N];

struct node {
    int sum, lmax, rmax, dat;
};

struct SegmentTree {
#define mid (l+r>>1)
#define ls (u<<1)
#define rs (u<<1|1)
#define ain (s<=l&&r<=t)
#define lin (s<=mid)
#define rin (t>=mid+1)
    int sum[N << 2], lmax[N << 2], rmax[N << 2], dat[N << 2];
    void pushup(int u) {
        sum[u] = sum[ls] + sum[rs];
        lmax[u] = max(lmax[ls], sum[ls] + lmax[rs]);
        rmax[u] = max(rmax[rs], sum[rs] + rmax[ls]);
        dat[u] = max(rmax[ls] + lmax[rs], max(dat[ls], dat[rs]));
    }
    void build(int l, int r, int u) {
        if (l == r) {
            sum[u] = lmax[u] = rmax[u] = dat[u] = a[l];
            return;
        }
        build(l, mid, ls);
        build(mid + 1, r, rs);
        pushup(u);
    }
    node ask(int s, int t, int l, int r, int u) {
        if (ain) return {sum[u], lmax[u], rmax[u], dat[u]};
        node ansl = {-inf, -inf, -inf, -inf};
        node ansr = {-inf, -inf, -inf, -inf};
        node ans = {0, -inf, -inf, -inf};
        if (lin) ansl = ask(s, t, l, mid, ls), ans.sum += ansl.sum;
        if (rin) ansr = ask(s, t, mid + 1, r, rs), ans.sum += ansr.sum;
        ans.dat = max(ansl.rmax + ansr.lmax, max(ansl.dat, ansr.dat));
        ans.lmax = max(ansl.lmax, ansl.sum + ansr.lmax);
        ans.rmax = max(ansr.rmax, ansr.sum + ansl.rmax);
        if (!lin) ans.lmax = max(ans.lmax, ansr.lmax);
        if (!rin) ans.rmax = max(ans.rmax, ansl.rmax);
        return ans;
    }
    void upd(int pos, int l, int r, int u, int val) {
        if (l == r) {
            sum[u] = lmax[u] = rmax[u] = dat[u] = val;
            return;
        }
        if (pos <= mid) upd(pos, l, mid, ls, val);
        else upd(pos, mid + 1, r, rs, val);
        pushup(u);
    }
} tr;

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];
    tr.build(1, n, 1);
    while (m--) {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1) {
            if (x > y) swap(x, y);
            cout << tr.ask(x, y, 1, n, 1).dat << "\n";
        } else {
            tr.upd(x, 1, n, 1, y);
        }
    }
}

signed main() {
    int T = 1; //cin >> T;
    while (T--) solve();
    return 0;
}

区间修改,查询区间GCD

这个问题可以差分单点做。

//
// Created by vv123 on 2022/9/9.
//
#include <bits/stdc++.h>
#define int long long
using namespace std;

const int mod = 998244353;
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f;

int n, m, a[N], b[N], t[N];

void add(int i, int x) {
    for (; i <= n; i += i & -i)
        t[i] += x;
}

int sum(int i) {
    int res = 0;
    for (; i; i -= i & -i)
        res += t[i];
    return res;
}

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}

struct SegmentTree {
#define mid (l+r>>1)
#define ls (u<<1)
#define rs (u<<1|1)
#define ain (s<=l&&r<=t)
#define lin (s<=mid)
#define rin (t>=mid+1)
    int g[N << 2];
    void pushup(int u) {
        g[u] = gcd(g[ls], g[rs]);
    }
    void build(int l, int r, int u) {
        if (l == r) {
            g[u] = b[l];
            return;
        }
        build(l, mid, ls);
        build(mid + 1, r, rs);
        pushup(u);
    }
    int ask(int s, int t, int l, int r, int u) {
        if (ain) return g[u];
        int res = 0;
        if (lin) res = gcd(res, ask(s, t, l, mid, ls));
        if (rin) res = gcd(res, ask(s, t, mid + 1, r, rs));
        return abs(res);
    }
    void add(int pos, int l, int r, int u, int val) {
        if (l == r) {
            g[u] += val;
            return;
        }
        if (pos <= mid) add(pos, l, mid, ls, val);
        else add(pos, mid + 1, r, rs, val);
        pushup(u);
    }
} tr;

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        b[i] = a[i] - a[i - 1];
        add(i, b[i]);
    }
    tr.build(1, n, 1);
    while (m--) {
        string op; int l, r, d;
        cin >> op >> l >> r;
        if (op == "Q") {
            cout << gcd(sum(l), tr.ask(l + 1, r, 1, n, 1)) << "\n";
        } else {
            cin >> d;
            add(l, d);
            if (r + 1 <= n) add(r + 1, -d);
            tr.add(l, 1, n, 1, d);
            if (r + 1 <= n) tr.add(r + 1, 1, n, 1, -d);
        }
    }
}

signed main() {
    int T = 1; //cin >> T;
    while (T--) solve();
    return 0;
}

区间加,区间求和

注意懒标记的处理

//
// Created by vv123 on 2022/8/31.
//
#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e6 + 10;
int a[N];

struct segmentTree {
#define mid (l+r>>1)
#define ls (u<<1)
#define rs (u<<1|1)
#define ain (s<=l&&r<=t)
#define lin (s<=mid)
#define rin (t>=mid+1)
#define len (r-l+1)
#define llen (mid-l+1)
#define rlen (r-mid)
    int sum[N], laz[N];

    void pushup(int u) {
        sum[u] = sum[ls] + sum[rs];
    }

    void pushdown(int l, int r, int u) {
        if (laz[u]) {
            sum[ls] += laz[u] * llen;
            sum[rs] += laz[u] * rlen;
            laz[ls] += laz[u];
            laz[rs] += laz[u];
            laz[u] = 0;
        }
    }

    void build(int l, int r, int u) {
        if (l == r) { sum[u] = a[l]; return; }
        build(l, mid, ls); build(mid + 1, r, rs);
        pushup(u);
    }

    void upd(int s, int t, int l, int r, int u, int k) {
        if (ain) {
            sum[u] += k * len;
            laz[u] += k;
            return;
        }
        pushdown(l, r, u);
        if (lin) upd(s, t, l, mid, ls, k);
        if (rin) upd(s, t, mid + 1, r, rs, k);
        pushup(u);
    }

    int ask(int s, int t, int l, int r, int u) {
        int res = 0;
        if (ain) return sum[u];
        pushdown(l, r, u);
        if (lin) res += ask(s, t, l, mid, ls);
        if (rin) res += ask(s, t, mid + 1, r, rs);
        return res;
    }
} tr;

signed main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    tr.build(1, n, 1);
    while (m--) {
        string op; int l, r, x;
        cin >> op;
        if (op == "Q") {
            cin >> l >> r;
            cout << tr.ask(l, r, 1, n, 1) << "\n";
        } else {
            cin >> l >> r >> x;
            tr.upd(l, r, 1, n, 1, x);
        }
    }
    return 0;
}

扫描线

//
// Created by vv123 on 2022/9/9.
//
//存板子!
#include <stdio.h>
#include <iostream>
#include <algorithm>
#define lson (x << 1)
#define rson (x << 1 | 1)
#define ll double
using namespace std;
const int MAXN = 1e6 + 10;


int n, cnt = 0;
ll x1, y1, x2, y2, X[MAXN << 1];

struct ScanLine {
    ll l, r, h;
    int mark;
//  mark用于保存权值 (1 / -1)
    bool operator < (const ScanLine &rhs) const {
        return h < rhs.h;
    }
} line[MAXN << 1];

struct SegTree {
    int l, r, sum;
    ll len;
//  sum: 被完全覆盖的次数;
//  len: 区间内被截的长度。
} tree[MAXN << 2];

void build_tree(int x, int l, int r) {
//  我觉得最不容易写错的一种建树方法
    tree[x].l = l, tree[x].r = r;
    tree[x].len = 0;
    tree[x].sum = 0;
    if(l == r)
        return;
    int mid = (l + r) >> 1;
    build_tree(lson, l, mid);
    build_tree(rson, mid + 1, r);
    return;
}

void pushup(int x) {
    int l = tree[x].l, r = tree[x].r;
    if(tree[x].sum /* 也就是说被覆盖过 */ )
        tree[x].len = X[r + 1] - X[l];
//      更新长度
    else
        tree[x].len = tree[lson].len + tree[rson].len;
//      合并儿子信息
}

void edit_tree(int x, ll L, ll R, int c) {
    int l = tree[x].l, r = tree[x].r;
//  注意,l、r和L、R的意义完全不同
//  l、r表示这个节点管辖的下标范围
//  而L、R则表示需要修改的真实区间
    if(X[r + 1] <= L || R <= X[l])
        return;
//  这里加等号的原因:
//  假设现在考虑 [2,5], [5,8] 两条线段,要修改 [1,5] 区间的sum
//  很明显,虽然5在这个区间内,[5,8] 却并不是我们希望修改的线段
//  所以总结一下,就加上了等号
    if(L <= X[l] && X[r + 1] <= R) {
        tree[x].sum += c;
        pushup(x);
        return;
    }
    edit_tree(lson, L, R, c);
    edit_tree(rson, L, R, c);
    pushup(x);
}

int main() {
    int kase = 0;
    while (scanf("%d", &n) && n) {
        for(int i = 1; i <= n; i++) {
            scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
            X[2 * i - 1] = x1, X[2 * i] = x2;
            line[2 * i - 1] = (ScanLine) {x1, x2, y1, 1};
            line[2 * i] = (ScanLine) {x1, x2, y2, -1};
//      一条线段含两个端点,一个矩形的上下边都需要扫描线扫过
        }
        n <<= 1;
//  直接把 n <<= 1 方便操作
        sort(line + 1, line + n + 1);
        sort(X + 1, X + n + 1);
        int tot = unique(X + 1, X + n + 1) - X - 1;
//  去重最简单的方法:使用unique!(在<algorithm>库中)
        build_tree(1, 1, tot - 1);
//  为什么是 tot - 1 :
//  因为右端点的对应关系已经被篡改了嘛…
//  [1, tot - 1]描述的就是[X[1], X[tot]]
        ll ans = 0;
        for(int i = 1; i < n /* 最后一条边是不用管的 */ ; i++) {
            edit_tree(1, line[i].l, line[i].r, line[i].mark);
//      先把扫描线信息导入线段树
            ans += tree[1].len * (line[i + 1].h - line[i].h);
//      然后统计面积
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n", ++kase, ans);
    }

    return 0;
}

区间加法和乘法,区间求和

注意多种懒标记的处理

//
// Created by vv123 on 2022/4/24.
//
#include <bits/stdc++.h>
#define ll long long
using namespace std;

#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<15,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<15],*frS=frBB,*frT=frBB;
template<typename T>
inline void read(T &x){
    x=0;char c=getchar();
    while(!isdigit(c))c=getchar();
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
}

const int N = 4e5 + 10;
int mod = 998244353;

int n, m, a[N];
ll add[N], mul[N], sum[N];
#define mid (l+r>>1)
#define len (r-l+1)
#define llen (mid-l+1)
#define rlen (r-mid)
#define ls (i<<1)
#define rs (i<<1|1)
#define allin s <= l && r <= t  //[s,t]与[l,r]一定有交集,只需考虑三种情况
#define lsin s <= mid
#define rsin t >= mid + 1

inline void pushup(int i) {
    sum[i] = (sum[ls] + sum[rs]) % mod;
}
inline void pushdown(int l, int r, int i) {
    if (mul[i] != 1) {
        (mul[ls] *= mul[i]) %= mod; (mul[rs] *= mul[i]) %= mod;
        (add[ls] *= mul[i]) %= mod; (add[rs] *= mul[i]) %= mod;
        (sum[ls] *= mul[i]) %= mod; (sum[rs] *= mul[i]) %= mod;
        mul[i] = 1;
    }
    if (add[i]) {
        (sum[ls] += add[i] * llen) %= mod; (sum[rs] += add[i] * rlen) %= mod;
        (add[ls] += add[i]) %= mod; (add[rs] += add[i]) %= mod;
        add[i] = 0;
    }
}
void Build(int l, int r, int i) {
    mul[i] = 1;
    if (l == r) { sum[i] = a[l]; return; }
    Build(l, mid, ls); Build(mid + 1, r, rs);
    pushup(i);
}
void Add(int s, int t, int l, int r, int i, int k) {
    if (allin) {
        (sum[i] += k * len) %= mod;
        (add[i] += k) %= mod;
        return;
    }
    pushdown(l, r, i);
    if (lsin) Add(s, t, l, mid, ls, k);
    if (rsin) Add(s, t, mid + 1, r, rs, k);
    pushup(i);
}
void Mul(int s, int t, int l, int r, int i, int k) {
    if (allin) {
        (add[i] *= k) %= mod;
        (mul[i] *= k) %= mod;
        (sum[i] *= k) %= mod;
        return;
    }
    pushdown(l, r, i);
    if (lsin) Mul(s, t, l, mid, ls, k);
    if (rsin) Mul(s, t, mid + 1, r, rs, k);
    pushup(i);
}
ll Query(int s, int t, int l, int r, int i) {
    ll res = 0;
    if (allin) return sum[i];
    pushdown(l, r, i);
    if (lsin) (res += Query(s, t, l, mid, ls)) %= mod;
    if (rsin) (res += Query(s, t, mid + 1, r, rs)) %= mod;
    return res;
}

int main() {
    read(n); read(mod);
    for (int i = 1; i <= n; i++) read(a[i]);
    Build(1, n, 1);
    read(m);
    while(m--) {
        int op, s, t, k;
        read(op); read(s); read(t);
        if (op == 1) {
            read(k); Mul(s, t, 1, n, 1, k);
        } else if (op == 2) {
            read(k); Add(s, t, 1, n, 1, k);
        } else {
            printf("%lld\n", Query(s, t, 1, n, 1));
        }
    }
    return 0;
}
posted @   _vv123  阅读(48)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示