首页 > 其他分享 >【线段树入门】P3373 线段树 2(区间乘加)

【线段树入门】P3373 线段树 2(区间乘加)

时间:2023-12-12 09:44:06浏览次数:26  
标签:int mid 线段 cin long P3373 update 乘加 define

//笔记-自用
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("unroll-loops")
#define _CRT_SECURE_NO_WARNINGS
#define All(a) a.begin(),a.end()
#define INF 2147483647
#include<bits/stdc++.h>
#include<numeric>
using namespace std;
typedef unsigned long long ull;
#define int long long//再也不用担心开longlong了><
typedef pair<int, int>PII;

int mod;
#define lc p<<1
#define rc p<<1|1
const int N = 1e5 + 5;
struct node {
    int l, r, val, mul, add;
}tr[N*4];
int w[N];

void pushup(int p) {//不变
    tr[p].val = tr[lc].val + tr[rc].val;
    tr[p].val %= mod;
}

void pushdown(int p) {//先乘后加 mul懒标记重置为1 区间修改:区间值*mul+区间长*add  mul懒标记:乘上mul  add懒标记:乘上mul并且加上add
    tr[lc].val = tr[p].mul * tr[lc].val + tr[p].add * (tr[lc].r - tr[lc].l + 1);
    tr[rc].val = tr[p].mul * tr[rc].val + tr[p].add * (tr[rc].r - tr[rc].l + 1);
    tr[lc].mul *= tr[p].mul;
    tr[rc].mul *= tr[p].mul;
    tr[lc].add = (tr[lc].add * tr[p].mul) + tr[p].add;
    tr[rc].add = (tr[rc].add * tr[p].mul) + tr[p].add;
    tr[lc].val %= mod; tr[rc].val %= mod;
    tr[lc].mul %= mod; tr[rc].mul %= mod;
    tr[lc].add %= mod; tr[rc].add %= mod;
    tr[p].mul = 1;
    tr[p].add = 0;
}

void build(int p, int l, int r) {//不变 mul初始值为1
    tr[p] = { l,r,w[l],1,0 };
    if (l == r)return;
    int mid = tr[p].l + tr[p].r >> 1;
    build(lc, l, mid);
    build(rc, mid + 1, r);
    pushup(p);
}

void update(int p, int x, int y, int mul, int add) {//类似
    if (x <= tr[p].l && tr[p].r <= y) {
        tr[p].val = mul * tr[p].val + add*(tr[p].r-tr[p].l+1);
        tr[p].mul *= mul;
        tr[p].add = tr[p].add * mul + add;
        tr[p].val %= mod; tr[p].mul %= mod; tr[p].add %= mod;
        return;
    }
    int mid = tr[p].l + tr[p].r >> 1;
    pushdown(p);
    if (x <= mid)update(lc, x, y, mul, add);
    if (y > mid)update(rc, x, y, mul, add);
    pushup(p);
}


int query(int p, int x, int y) {//类似
    if (x <= tr[p].l && tr[p].r <= y) {        
        return tr[p].val;
    }
    int mid = tr[p].l + tr[p].r >> 1;
    pushdown(p);
    int res = 0;
    if (x <= mid)res += query(lc, x, y);
    if (y > mid)res += query(rc, x, y);
    return res;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, q;
    cin >> n >> q >> mod;
    for (int i = 1; i <= n; i++)cin >> w[i];
    build(1, 1, n);
    while (q--) {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1) {
            int k;
            cin >> k;
            update(1, x, y, k, 0);
        }
        else if (op == 2) {
            int k;
            cin >> k;
            update(1, x, y, 1, k);
        }
        else {
            cout << query(1, x, y)%mod << "\n";
        }
    }

}

 

标签:int,mid,线段,cin,long,P3373,update,乘加,define
From: https://www.cnblogs.com/iscr/p/17896096.html

相关文章

  • 2020年初一初二集训队(线段树) 基本操作
    其他线段树详解与实现-知乎⁤(zhihu.com)线段树-OIWiki(oi-wiki.org) 线段树学习笔记-xujindong的博客-洛谷博客(luogu.com.cn)  简介线段树(segmenttree)是一种二叉搜索树,也是平衡二叉树,它的每一个结点对应一个区间[L,R],叶子结点对应的区间只有一个......
  • 线段树模板区间加(含懒标记)
    constintN=1e5+10;intn,m;inta[N];structTree{ intl,r; llsum,add; }tr[4*N];voidbuild(intu,intl,intr){ //l=tr[u].l;r=tr[u].r; //注释掉的部分是典型的错误,对于build过程中我们是初始化编号对应区间节点,上面赋值逻辑反了 tr[u]={l,r}; if(l==r)t......
  • 线段树
    首先是建树我们先构建整棵树的框架 structnode{intl,r;stringdata;}g[N*4];//不一定非要构建结构体,看题目需求,如果不涉及左右范围的话就可以直接构造数组 //n表示的是树上每个结点的数值,比如说第一个结点为1,那莫第一个结点的左子树为2,右子树为3//l(是......
  • 【数据结构】线段树 (二) 学习笔记
    线段树(二)点击查看:线段树(一)学习笔记本文介绍权值线段树与动态开点线段树,(可能后面还会加线段树合并等等)。权值线段树线段树的动态开点线段树合并推荐题目&&参考资料&&拓展阅读《算法竞赛进阶指南》0x43线段树P3870 [TJOI2009]开关P1438 无聊的数列P1253 扶苏的问......
  • 李超线段树
    问题:洛谷P4097在平面直角坐标系维护两个操作:1.加入一条线段。2.求目前平面直角坐标系中截一条直线\(x=k\)中与线段交点\(y\)最大的是那一条线段。解决:李超线段树模板。首先建一个以\(x\)为区间的线段树。和普通线段树的主要区别是在对懒标记的处理上,这里是是没有单独的下......
  • 线段树优化建图
    问题:CF786B给定一个\(n\)个点,\(m\)次连边的有向图,有三种连边(均有边权)方式:1.\(u\tov\),一条\(u\)指向\(v\)的连边。2.\(u\to[l,r]\),\(u\)向在区间\([l,r]\)的点分别连一条边。3.\([l,r]\tov\),在区间\([l,r]\)的点向\(v\)分别连一条边。问从\(1\)点出发,到各个点的最短路。......
  • 像使用stl一样使用线段树 ——AtCoder Library(转载https://zhuanlan.zhihu.com/p/459
    地址:https://zhuanlan.zhihu.com/p/459579152 我这里翻译一下官方的文档。首先需要满足几个性质。(注意 ∗ 是个操作,不是单纯的一个乘号)1)操作满足结合律即 (a∗b)∗c=a∗(b∗c)2)操作需要有个幺元(基本元/单位元)a∗e=e∗a=a如果你有这个一个序列S,长度为N ,接下......
  • 【2024省选冲刺计划】数据结构相关-线段树进阶
    线段树进阶0x01李超线段树FZPJ4519[2021冬令营模拟]上古遗迹【题目背景】“沙……沙……沙……”独行者的脚步一次次被刻进沙漠中,干冷的风携沙尘在男子的四围穿过。“该死……这沙尘什么时候才能消停会儿……”男子止不住地咳嗽,随即停了下来,开始查看便携式投影设备上的信......
  • 树状数组和线段树
    树状数组:1.将某一个数加上k2.求出某区间每一个数的和#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;lln,m,a[500000+10];lllowbit(llx){returnx&(-x);}voidadd(llx,llk){ while(x<=n){ a[x]+=k; x+=lowbit(x); }}llquery(llx){ ll......
  • 线段树优化建图
    CF786B题意:定义\((u,v,w)\)表示\(u\)向\(v\)连了边权为\(w\)的边。有三种连边操作\((u,v,w)\)\(\foralli\in[l,r],(u,i,w)\)\(\foralli\in[l,r],(i,u,w)\)求最短路。暴力加边是\(O(nm)\)的,考虑优化。可以把图建到线段树上,线段树每个结点向左右儿子连\(w......