首页 > 其他分享 >线段树维护区间等差数列

线段树维护区间等差数列

时间:2024-03-10 13:22:50浏览次数:18  
标签:return int 线段 mid Seg sum 区间 id 等差数列

线段树维护区间等差数列

我们采用用两个懒标记分别维护等 差数列首项 k 和 公差 d

维护时有个细节是假如我有左右两个区间需要合并信息时

我们对于左边还是 k 和 d

但是对于右边信息此时 k 应该变成 k + len * d, 公差还是 d

len表示的是右边区间长度

牛牛的等差数列

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
typedef long long ll;

const int N = 2e5 + 100;
const int mod = 111546435, inv2 = 55773218;

int a[N];

struct node {
    int sum, k, d;
} Seg[N * 4];

void settag(int id, int k, int d, int len) {
    Seg[id].k += k; Seg[id].d += d;
    Seg[id].k %= mod; Seg[id].d %= mod;
    Seg[id].sum += (k + k + d * (len - 1) % mod) % mod * len % mod * inv2 % mod;
}

void pushdown(int id, int l, int r) {
    int mid = l + r >> 1;
    int k = Seg[id].k, d = Seg[id].d;
    if (k || d) {
        settag(id * 2, k, d, mid - l + 1);
        k += (mid - l + 1) * d; k %= mod;
        settag(id * 2 + 1, k, d, r - mid);
        Seg[id].k = Seg[id].d = 0;
    }
}

void pushup(int id) {
    Seg[id].sum = (Seg[id * 2].sum + Seg[id * 2 + 1].sum) % mod;
}

void build(int id, int l, int r) {
    Seg[id] = {0, 0, 0};
    if (l == r) {
        Seg[id].sum = a[l] % mod;
        return;
    }
    int mid = l + r >> 1;
    build(id * 2, l, mid); build(id * 2 + 1, mid + 1, r);
    pushup(id);
}    

void modify(int id, int l, int r, int x, int y, int k, int d) {
    if (x <= l && y >= r) {
        int len = r - l + 1;
        settag(id, k, d, len);
        return;
    }
    int mid = l + r >> 1;
    pushdown(id, l, r);
    if (x > mid) modify(id * 2 + 1, mid + 1, r, x, y, k, d);
    else if (y <= mid) modify(id * 2, l, mid, x, y, k, d);
    else {
        modify(id * 2, l, mid, x, mid, k, d);
        int len = mid - x + 1;
        k += len * d; k %= mod;
        modify(id * 2 + 1, mid + 1, r, mid + 1, y, k, d);
    }
    pushup(id);
}

int query(int id, int l, int r, int x, int y) {
    if (x <= l && y >= r) return Seg[id].sum;
    pushdown(id, l, r);
    int mid = l + r >> 1, ans = 0;
    if (x <= mid) ans += query(id * 2, l, mid, x, y), ans %= mod;
    if (y > mid) ans += query(id * 2 + 1, mid + 1, r, x, y), ans %= mod;
    return ans;
}

void solve() {
    int n; cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    build(1, 1, n);
    int q; cin >> q;
    while (q--) {
        int op; cin >> op;
        if (op == 1) {
            int l, r, k, d; cin >> l >> r >> k >> d;
            modify(1, 1, n, l, r, k % mod, d % mod);
        } else {
            int l, r, m; cin >> l >> r >> m;
            cout << query(1, 1, n, l, r) % m << endl;
        }
    }
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

    solve();

    return 0;
}
View Code

Space Harbour
这题和上题差不多,但是不知道为什么我线段树一直越界

在线段树各个函数中特判了下边界才过

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
typedef long long ll;

const int N = 1e6 + 100;

int a[N], v[N], n, m, q;
set<int> s;

struct node {
    int sum, k, d;
} Seg[N * 4];

bool check(int x) {
    return x >= 1 && x <= n;
}

void pushup(int id) {
    if (id * 2 + 1 > N * 3) return;
    Seg[id].sum = Seg[id * 2].sum + Seg[id * 2 + 1].sum;
}

void settag(int id, int k, int d, int len) {
    if (id > N * 3) return;
    Seg[id].k = k; Seg[id].d = d;
    Seg[id].sum = (k + k + d * (len - 1)) * len / 2;
}

void pushdown(int id, int l, int r) {
    if (id > N * 3) return;
    int mid = l + r >> 1;
    int k = Seg[id].k, d = Seg[id].d;
    if (k) {
        settag(id * 2, k, d, mid - l + 1);
        k += (mid - l + 1) * d;
        settag(id * 2 + 1, k, d, r - mid);
        Seg[id].k = Seg[id].d = 0;
    }
}

void build(int id, int l, int r) {
    if (id > N * 3) return;
    if (l == r) {
        if (v[l]) Seg[id].sum = 0;
        else {
            auto it = s.lower_bound(l);
            if (check(*it) && check(*prev(it))) Seg[id].sum = (*it - l) * (v[*prev(it)]);
            else Seg[id].sum = 0;
        }
        // if (l == 2) cout << a[l] << ' ' << Seg[id].sum << endl;
        return;
    }
    int mid = l + r >> 1;
    build(id * 2, l, mid); build(id * 2 + 1, mid + 1, r);
    pushup(id);
}

void modify(int id, int l, int r, int x, int y, int k, int d) {
    if (id > N * 3) return;
    if (x == l && y == r) {
        settag(id, k, d, r - l + 1);
        return;
    }
    int mid = l + r >> 1;
    pushdown(id, l, r);
    if (x > mid) modify(id * 2 + 1, mid + 1, r, x, y, k, d);
    else if (y <= mid) modify(id * 2, l, mid, x, y, k, d);
    else {
        modify(id * 2, l, mid, x, mid, k, d);
        int len = mid - x + 1;
        k += len * d;
        modify(id * 2 + 1, mid + 1, r, mid + 1, y, k, d);
    }
    pushup(id);
}

int query(int id, int l, int r, int x, int y) {
    if (id > N * 3) return 0;
    if (x <= l && y >= r) return Seg[id].sum;
    int mid = l + r >> 1, ans = 0;
    pushdown(id, l, r);
    if (x <= mid) ans += query(id * 2, l, mid, x, y);
    if (y > mid) ans += query(id * 2 + 1, mid + 1, r, x, y);
    return ans;
}   

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

    build(1, 1, n);

    while (q--) {
        int op, x, y; cin >> op >> x >> y;
        if (op == 1) {
            v[x] = y;
            auto it = s.lower_bound(x);
            int l = *prev(it), r = *it;
            if (check(l) && check(r)) {
                modify(1, 1, n, l + 1, x - 1, v[l] * (x - l - 1), -v[l]);
                modify(1, 1, n, x, x, 0, 0);
                modify(1, 1, n, x + 1, r - 1, y * (r - x - 1), -y);   
            } else if (check(l) && !check(r)) {
                modify(1, 1, n, l + 1, x - 1, v[l] * (x - l - 1), -v[l]);
                modify(1, 1, n, x, x, 0, 0);
            } else if (check(r) && !check(l)) {
                modify(1, 1, n, x, x, 0, 0);
                modify(1, 1, n, x + 1, r - 1, y * (r - x - 1), -y); 
            } else {
                modify(1, 1, n, x, x, 0, 0);
            }
            s.insert(x);
        } else {
            cout << query(1, 1, n, x, y) << endl;
        }
    }
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

    solve();

    return 0;
}
View Code

 

标签:return,int,线段,mid,Seg,sum,区间,id,等差数列
From: https://www.cnblogs.com/zhujio/p/18064034

相关文章

  • 线段树合并 & DSU on tree
    线段树合并&DsuontreeCF600E线段树合并,每个节点下维护子树下每个颜色的数量,建立权值线段树复杂度证明:叶子节点\(O(logm)\)Dsuontree重儿子信息保留,轻儿子信息递归计算一次,合并一次。复杂度证明:对于一个点,最多经过\(O(\logn)\)条轻边,第一次被递归执行一次,每次被当......
  • [蓝桥杯 2019 省 B] 等差数列
    实际上这道题不需要先排序再求gcd,因为无论是哪两项之前作差,都不会影响最后的gcd的结果。因为公差是从a2-a1开始算的,因此i=1时要特殊处理,不能把a1-0计入贡献,否则会算出错误的gcd。即作差时不要加上a1-0,统计最值时不要漏掉a1#include<iostream>#include<stdio.h>#include<a......
  • 线段树写法勘误
    今天下午写这题 牛牛的等差数列 时瞪了一下午没找到为什么wa了,留个记录提醒一下自己后面发现好像是线段树modify函数写错了一般modify函数我都是写成这样的 但是写这题mid卡在修改区间中间这种写法有点难处理于是我就写了这种写法 一直在wa,问题出在这里 ......
  • 通达信买卖区间信号指标公式源码副图
    {通达信买卖区间信号指标公式源码副图}A14:=MA(CLOSE,20);A15:=(CLOSE>MA(CLOSE,5));A16:=(MA(CLOSE,5)>MA(CLOSE,10));A17:=(CLOSE>MA(CLOSE,10));A18:=(MA(CLOSE,5)>MA(CLOSE,20));A19:=(CLOSE>MA(CLOSE,20));A10:=REF(A14,1);A11:=(A14>A10);AVX:......
  • 高德地图api标记点和线段重合点击响应问题
    问题现象:现在地图上放置了line和marker,marker在line的上层显示这时line和marker同时存在,当line和marker有重合部分并点击重合点时,只响应line对应的click事件,而位于下方的line无法响应对应的click事件如图:原因:点击事件被上层的marker阻挡,marker并未注册点击事件解决方案在am......
  • chapter7-贪心策略-区间贪心
    2.区间贪心区间贪心也是一种常见的贪心策略类的题型。它是指当有多个不同的区间存在,且这些区间有可能相互重叠的时候,如何选择才能从众多区间中,选取最多的两两互不相交的区间。今年暑假不AC杭电OJ2037看尽可能多的节目:贪心策略问题分析:区间贪心和简单贪心不同的地方在于决......
  • 由区间合并->离散化
    `#include<iostream>#include<cstring>#include<vector>#include<algorithm>usingnamespacestd;typedefpair<int,int>PII;//数对type-类型define-定义pair-一对constintN=300......
  • (36/60)无重叠区间、划分字母区间、合并区间
    无重叠区间leetcode:435.无重叠区间贪心法思路去掉最少的区间数就是最少重叠区间对的个数。(成对的算,因为一对里面需要去掉一个)类似射气球的处理方式。左边界法:按左边界从小到大排序。遍历每个元素。取当前元素右边界为right判断是否重叠。如果[i]right>[i+1]left......
  • 代码随想录算法训练营第三十六天 | 56. 合并区间,763.划分字母区间,435. 无重叠区间
    435.无重叠区间 已解答中等 相关标签相关企业 给定一个区间的集合 intervals ,其中 intervals[i]=[starti,endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。 示例1:输入:intervals=[[1,2],[2,3],[3,4],[1,3]]输出:1解......
  • 代码随想录算法训练营第三十六天| ● 435. 无重叠区间 ● 763.划分字母区间 ● 56.
    无重叠区间 题目链接:435.无重叠区间-力扣(LeetCode)思路:我的思路是先将所有区间按左端点从小到大排序,左端点相同时右端点从小到大排序。接下来遍历数组,如果下一个区间与该区间有重叠部分,count加1,同时遍历下下一个区间(下一个区间被视为删除),同时如果下一个区间被包含在该区间中,......