P7497 四方喝彩 Solution

Description

给定序列 a = ( a 1 , a 2 , ⋯   , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,,an),有 m m m 个操作,分四种:

  • add ⁡ ( l , r , v ) \operatorname{add}(l,r,v) add(l,r,v):对于所有 i ∈ [ l , r ] i \in [l,r] i[l,r] 执行 a i ← a i + v a_i \gets a_i+v aiai+v.
  • mul ⁡ ( l , r , v ) \operatorname{mul}(l,r,v) mul(l,r,v):对于所有 i ∈ [ l , r ] i \in [l,r] i[l,r] 执行 a i ← a i × v a_i \gets a_i\times v aiai×v.
  • freeze ⁡ ( l , r , x ) \operatorname{freeze}(l,r,x) freeze(l,r,x):区间 [ l , r ] [l,r] [l,r] 在接下来的 x x x 次操作中被冻结,不会受修改操作影响,已有的冻结效果不会被替换.
  • query ⁡ ( l , r ) \operatorname{query}(l,r) query(l,r):求 ( ∑ i = l r a i )   m o d   ( 1 0 9 + 7 ) (\sum\limits_{i=l}^r a_i) \bmod (10^9+7) (i=lrai)mod(109+7).

Limitations

1 ≤ n , m ≤ 2 × 1 0 5 1 \le n,m \le 2\times 10^5 1n,m2×105
0 ≤ a i , v ≤ 1 0 9 + 7 0 \le a_i,v \le 10^9+7 0ai,v109+7
设当前为第 t t t 次操作,则 0 ≤ x ≤ m − k 0 \le x \le m-k 0xmk
1 s , 512 MB 1\text{s},512\text{MB} 1s,512MB

Solution

freeze ⁡ \operatorname{freeze} freeze 操作拆成冻结和解冻两个操作,将解冻操作按解冻时间记在邻接表上.
考虑 add ⁡ \operatorname{add} add,由于区间可能部分冻结,故乘的长度不是 ( r − l + 1 ) (r-l+1) (rl+1) 而是未封锁元素个数,需要维护.
考虑 mul ⁡ \operatorname{mul} mul,同样由于区间可能部分冻结,不能直接 × v \times v ×v,而是将未冻结部分 × v \times v ×v,所以需要分开维护未冻结部分和冻结部分的和.
考虑多个冻结操作重叠,由于合并它们很麻烦,所以直接叠加,等到完全解冻才继续 pushdown,所以维护的是冻结次数而不是是否冻结
写的时候注意细节,具体可以看代码。

Code

8.06 KB , 1.12 s , 31.29 MB    (in   total,   C++20   with   O2) 8.06\text{KB},1.12\text{s},31.29\text{MB}\;\texttt{(in total, C++20 with O2)} 8.06KB,1.12s,31.29MB(in total, C++20 with O2)

// Problem: P7497 四方喝彩
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7497
// Memory Limit: 512 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;

template<class T>
bool chmax(T &a, const T &b){
	if(a < b){ a = b; return true; }
	return false;
}

template<class T>
bool chmin(T &a, const T &b){
	if(a > b){ a = b; return true; }
	return false;
}

template <int MOD>
struct modint {
    int val;
    static int norm(const int& x) { return x < 0 ? x + MOD : x; }
    modint inv() const {
        int a = val, b = MOD, u = 1, v = 0, t;
        while (b > 0) t = a / b, swap(a -= t * b, b), swap(u -= t * v, v);
        return modint(u);
    }
    modint() : val(0) {}
    modint(const int& m) : val(norm(m % MOD)) {}
    modint(const long long& m) : val(norm(m % MOD)) {}
    modint operator-() const { return modint(norm(-val)); }
    bool operator==(const modint& o) { return val == o.val; }
    bool operator!=(const modint &o) { return val != o.val; }
    bool operator<(const modint& o) { return val < o.val; }
    bool operator>(const modint& o) { return val > o.val; }
    bool operator<=(const modint& o) { return val <= o.val; }
    bool operator>=(const modint& o) { return val >= o.val; }
    modint& operator++() { return *this += 1; }
    modint operator++(int) { modint temp = *this; ++(*this); return temp; }
    modint& operator--() { return *this -= 1; }
    modint operator--(int) { modint temp = *this; --(*this); return temp; }
    modint& operator+=(const modint& o) { return val = (1ll * val + o.val) % MOD, *this; }
    modint& operator-=(const modint& o) { return val = norm(1ll * val - o.val), *this; }
    modint& operator*=(const modint& o) { return val = static_cast<int>(1ll * val * o.val % MOD), *this; }
    modint& operator/=(const modint& o) { return *this *= o.inv(); }
    modint& operator^=(const modint& o) { return val ^= o.val, *this; }
    modint& operator>>=(const modint& o) { return val >>= o.val, *this; }
    modint& operator<<=(const modint& o) { return val <<= o.val, *this; }
    modint operator-(const modint& o) const { return modint(*this) -= o; }
    modint operator+(const modint& o) const { return modint(*this) += o; }
    modint operator*(const modint& o) const { return modint(*this) *= o; }
    modint operator/(const modint& o) const { return modint(*this) /= o; }
    modint operator^(const modint& o) const { return modint(*this) ^= o; }
    modint operator>>(const modint& o) const { return modint(*this) >>= o; }
    modint operator<<(const modint& o) const { return modint(*this) <<= o; }
    friend std::istream& operator>>(std::istream& is, modint& a) {
        long long v;
        return is >> v, a.val = norm(v % MOD), is;
    }
    friend std::ostream& operator<<(std::ostream& os, const modint& a) { return os << a.val; }
    friend std::string tostring(const modint& a) { return std::to_string(a.val); }
    template <class T>
    friend modint qpow(const modint& a, const T& b) {
        modint x = a, res = 1;
        for (T p = b; p; x *= x, p >>= 1)
            if (p & 1) res *= x;
        return res;
    }
};

using Z = modint<1000000007>;

struct Node {
    int l, r, size, blocks;
    Z suma, sumb, add, mul;
};

using Tree = vector<Node>;

int ls(int u) { return u * 2 + 1; }
int rs(int u) { return u * 2 + 2; }

void pushup(Tree& tr, int u) {
    if (tr[u].blocks == 0) {
        tr[u].suma = tr[ls(u)].suma + tr[rs(u)].suma;
        tr[u].sumb = tr[ls(u)].sumb + tr[rs(u)].sumb;
        tr[u].size = tr[ls(u)].size + tr[rs(u)].size;
    }
}

void apply(Node& rt, Node& son) {
    if (son.blocks == 0) {
        son.suma = son.suma * rt.mul + rt.add * son.size;
        son.add = son.add * rt.mul + rt.add;
        son.mul *= rt.mul;
    }
}

void pushdown(Tree& tr, int u) {
    apply(tr[u], tr[ls(u)]);
    apply(tr[u], tr[rs(u)]);
    tr[u].add = 0;
    tr[u].mul = 1;
}

void build(Tree& tr, int u, int l, int r, vector<int>& a) {
    tr[u].l = l;
    tr[u].r = r;
    tr[u].mul = 1;
    tr[u].add = 0;
    
    if (l == r) {
        tr[u].suma = a[l];
        tr[u].size = 1;
        return;
    }
    
    int mid = (l + r) >> 1;
    build(tr, ls(u), l, mid, a);
    build(tr, rs(u), mid + 1, r, a);
    pushup(tr, u);
}

void add(Tree& tr, int u, int l, int r, Z val) {
    if (tr[u].l > r || tr[u].r < l || tr[u].blocks > 0) {
        return;
    }
    if (l <= tr[u].l && tr[u].r <= r) {
        tr[u].suma += val * tr[u].size;
        tr[u].add += val;
        return;
    }
    
    int mid = (tr[u].l + tr[u].r) >> 1;
    pushdown(tr, u);
    if (l <= mid) {
        add(tr, ls(u), l, r, val);
    }
    if (r > mid) {
        add(tr, rs(u), l, r, val);
    }
    pushup(tr, u);
}

void mul(Tree& tr, int u, int l, int r, Z val) {
    if (tr[u].l > r || tr[u].r < l || tr[u].blocks > 0) {
        return;
    }
    if (l <= tr[u].l && tr[u].r <= r) {
        tr[u].suma *= val;
        tr[u].add *= val;
        tr[u].mul *= val;
        return;
    }
    
    int mid = (tr[u].l + tr[u].r) >> 1;
    pushdown(tr, u);
    if (l <= mid) {
        mul(tr, ls(u), l, r, val);
    }
    if (r > mid) {
        mul(tr, rs(u), l, r, val);
    }
    pushup(tr, u);
}

void block(Tree& tr, int u, int l, int r) {
    if (tr[u].l > r || tr[u].r < l) {
        return;
    }
    if (l <= tr[u].l && tr[u].r <= r) {
        if (tr[u].l < tr[u].r) {
            pushdown(tr, u);
        }
        if (tr[u].blocks == 0) {
            tr[u].sumb += tr[u].suma;
            tr[u].suma = 0;
            tr[u].size = 0;
        }
        tr[u].blocks++;
        return;
    }
    
    int mid = (tr[u].l + tr[u].r) >> 1;
    pushdown(tr, u);
    if (l <= mid) {
        block(tr, ls(u), l, r);
    }
    if (r > mid) {
        block(tr, rs(u), l, r);
    }
    pushup(tr, u);
}

void unblock(Tree& tr, int u, int l, int r) {
    if (tr[u].l > r || tr[u].r < l) {
        return;
    }
    if (l <= tr[u].l && tr[u].r <= r) {
        tr[u].blocks--;
        if (tr[u].blocks == 0) {
            if (tr[u].l == tr[u].r) {
                tr[u].suma += tr[u].sumb;
                tr[u].sumb = 0;
                tr[u].size = 1;
            }
            else {
                pushup(tr, u);
            }
        }
        return;
    }
    
    int mid = (tr[u].l + tr[u].r) >> 1;
    pushdown(tr, u);
    if (l <= mid) {
        unblock(tr, ls(u), l, r);
    }
    if (r > mid) {
        unblock(tr, rs(u), l, r);
    }
    pushup(tr, u);
}

Z query(Tree& tr, int u, int l, int r) {
    if (tr[u].l > r || tr[u].r < l) {
        return 0;
    }
    if (l <= tr[u].l && tr[u].r <= r) {
        return tr[u].suma + tr[u].sumb;
    }
    
    int mid = (tr[u].l + tr[u].r) >> 1;
    Z ans = 0;
    pushdown(tr, u);
    if (l <= mid) {
        ans += query(tr, ls(u), l, r);
    }
    if (r > mid) {
        ans += query(tr, rs(u), l, r);
    }
    return ans;
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, m;
	scanf("%d%d", &n, &m);
	
	vector<int> a(n);
	for (int i = 0; i < n; i++) {
	    scanf("%d", &a[i]);
	}
	
	Tree seg(n << 2);
	vector<vector<pair<int, int>>> blocks(m);
	build(seg, 0, 0, n - 1, a);
	
	for (int i = 0, op, l, r, v; i < m; i++) {
	    scanf("%d%d%d", &op, &l, &r);
	    l--, r--;
	    if (op == 1) {
	        scanf("%d", &v);
	        add(seg, 0, l, r, Z(v));
	    }
	    if (op == 2) {
	        scanf("%d", &v);
	        mul(seg, 0, l, r, Z(v));
	    }
	    if (op == 3) {
	        scanf("%d", &v);
	        block(seg, 0, l, r);
	        blocks[i + v].emplace_back(l, r);
	    }
	    if (op == 4) {
	        printf("%d\n", query(seg, 0, l, r).val);
	    }
	    
	    for (auto [le, ri] : blocks[i]) {
	        unblock(seg, 0, le, ri);
	    }
	}
	
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/963882.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android --- handler详解

handler 理解 handler 是一套Android 消息传递机制&#xff0c;主要用于线程间通信。 tips&#xff1a; binder/socket 用于进程间通信。 参考&#xff1a; Android 进程间通信-CSDN博客 handler 就是主线程在起了一个子线程&#xff0c;子线程运行并生成message &#xff0c;l…

【线程】基于阻塞队列的生产者消费者模型

文章目录 1 生产者消费者模型2 阻塞队列2.1 成员变量2.2 消费者操作2.3 生产者生产 3 总结 1 生产者消费者模型 在多线程环境中&#xff0c;生产者消费者模型是一种经典的线程同步模型&#xff0c;用于处理生产者线程与消费者线程之间的工作调度和资源共享问题。在这个模型中&a…

解决PyG安装中torch-sparse安装失败问题:详细指南

1 问题描述 最近在学习GNN&#xff0c;需要使用PyTorch Geometric&#xff08;PyG&#xff09;库。在安装PyG的过程中&#xff0c;遇到了torch-sparse安装失败的问题&#xff0c;错误提示为&#xff1a; ERROR: Failed building wheel for torch-sparse本文将详细记录问题的解…

4 [危机13小时追踪一场GitHub投毒事件]

事件概要 自北京时间 2024.12.4 晚间6点起&#xff0c; GitHub 上不断出现“幽灵仓库”&#xff0c;仓库中没有任何代码&#xff0c;只有诱导性的病毒文件。当天&#xff0c;他们成为了 GitHub 上 star 增速最快的仓库。超过 180 个虚假僵尸账户正在传播病毒&#xff0c;等待不…

【B站保姆级视频教程:Jetson配置YOLOv11环境(六)PyTorchTorchvision安装】

Jetson配置YOLOv11环境&#xff08;6&#xff09;PyTorch&Torchvision安装 文章目录 1. 安装PyTorch1.1安装依赖项1.2 下载torch wheel 安装包1.3 安装 2. 安装torchvisiion2.1 安装依赖2.2 编译安装torchvision2.2.1 Torchvisiion版本选择2.2.2 下载torchvisiion到Downloa…

自动化软件测试的基本流程

一、自动化测试的准备 1.1 了解测试系统 首先对于需要测试的系统我们需要按照软件需求说明书明确软件功能。这里以智慧养老系统作为案例进行测试&#xff0c;先让我们看看该系统的登录界面和用户管理界面。 登录界面&#xff1a; 登录成功默认界面&#xff1a; 用户管理界面…

前端力扣刷题 | 6:hot100之 矩阵

73. 矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 法一&#xff1a; var setZeroes function(matrix) {let setX new Set(); // 用于存储需要置零的行索引let setY new Set(); //…

SLAM技术栈 ——《视觉SLAM十四讲》学习笔记(一)

《视觉SLAM十四讲》学习笔记&#xff08;一&#xff09; 第2讲 初识SLAM习题部分 第3讲 三维空间刚体运动3.1 左手系与右手系3.2 齐次坐标3.3 旋转矩阵与变换矩阵3.4 正交群与欧式群3.5 旋转向量与欧拉角3.6 实践Eigen线性代数库3.6.1 QR分解(QR decomposition) 3.7 四元数到其…

自动驾驶---两轮自行车的自主导航

1 背景 无人驾驶汽车最早出现在DARPA的比赛中&#xff0c;从那个时刻开始&#xff0c;逐渐引起全球学者的注意&#xff0c;于是从上个世纪开始各大高校院所开始了无人汽车的研发。直到这两年&#xff0c;无人驾驶汽车才开始走进寻常百姓家&#xff0c;虽然目前市面上的乘用车还…

Spring Boot 2 快速教程:WebFlux处理流程(五)

WebFlux请求处理流程 下面是spring mvc的请求处理流程 具体步骤&#xff1a; 第一步&#xff1a;发起请求到前端控制器(DispatcherServlet) 第二步&#xff1a;前端控制器请求HandlerMapping查找 Handler &#xff08;可以根据xml配置、注解进行查找&#xff09; 匹配条件包括…

优选算法的灵动之章:双指针专题(一)

个人主页&#xff1a;手握风云 专栏&#xff1a;算法 一、双指针算法思想 双指针算法主要用于处理数组、链表等线性数据结构中的问题。它通过设置两个指针&#xff0c;在数据结构上进行遍历和操作&#xff0c;从而实现高效解决问题。 二、算法题精讲 2.1. 查找总价格为目标值…

Intel 与 Yocto 项目的深度融合:全面解析与平台对比

在嵌入式 Linux 领域&#xff0c;Yocto 项目已成为构建定制化 Linux 发行版的事实标准&#xff0c;广泛应用于不同架构的 SoC 平台。Intel 作为 x86 架构的领导者&#xff0c;在 Yocto 生态中投入了大量资源&#xff0c;为其嵌入式处理器、FPGA 和 AI 加速硬件提供了完整的支持…

算法刷题Day29:BM67 不同路径的数目(一)

题目链接 描述 解题思路&#xff1a; 二维dp数组初始化。 dp[i][0] 1, dp[0][j] 1 。因为到达第一行第一列的每个格子只能有一条路。状态转移 dp[i][j] dp[i-1][j] dp[i][j-1] 代码&#xff1a; class Solution: def uniquePaths(self , m: int, n: int) -> int: #…

98,【6】 buuctf web [ISITDTU 2019]EasyPHP

进入靶场 代码 <?php // 高亮显示当前 PHP 文件的源代码&#xff0c;通常用于调试或展示代码&#xff0c;方便用户查看代码逻辑 highlight_file(__FILE__);// 从 GET 请求中获取名为 _ 的参数值&#xff0c;并赋值给变量 $_ // 符号用于抑制可能出现的错误信息&#xff…

C++中常用的十大排序方法之4——希尔排序

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C中常用的排序方法之4——希尔排序的相…

字节iOS面试经验分享:HTTP与网络编程

字节iOS面试经验分享&#xff1a;HTTP与网络编程 &#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 目录 字节iOS面试经验分享&#xff1a;HTT…

音视频入门基础:RTP专题(7)——RTP协议简介

一、引言 本文对RTP协议进行简介。在简介之前&#xff0c;请各位先下载RTP的官方文档《RFC 3550》和《RFC 3551》。《RFC 3550》总共有89页&#xff0c;《RFC 3551》总共有44页。本文下面所说的“页数”是指在pdf阅读器中显示的页数&#xff1a; 二、RTP协议简介 根据《RFC 35…

SQLGlot:用SQLGlot解析SQL

几十年来&#xff0c;结构化查询语言&#xff08;SQL&#xff09;一直是与数据库交互的实际语言。在一段时间内&#xff0c;不同的数据库在支持通用SQL语法的同时演变出了不同的SQL风格&#xff0c;也就是方言。这可能是SQL被广泛采用和流行的原因之一。 SQL解析是解构SQL查询…

Java 大视界 -- Java 大数据在智能电网中的应用与发展趋势(71)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

想表示消息返回值为Customer集合

道奈特(240***10) 14:34:55 EA中序列图。我想表示消息返回值为 Customer 集合。目前只有一个Customer实体类&#xff0c;我需要另外新建一个CustomerList 类吗&#xff1f; 潘加宇(35***47) 17:01:26 不需要。如果是分析&#xff0c;在类的操作中&#xff0c;定义一个参数&…