问题描述:

给定一个数列,数列中所有元素都初始化为0,对其执行多种区间操作

操作1:add修改:对区间[L,R]内的所有数加c

操作2:multi修改:对区间[L,R]内所有数乘以c

操作3:change操作:把区间[L,R]内所有数改为c

操作4:sum操作:对区间中的每个数的p次方求和。1<=p<=3

输入:

有不超过10个测试用例。

对于每个测试用例,第一行包含两个数字n和m,表示有n个整数和m个操作。其中,1 <= n, m <= 100,000。

接下来的m行,每行包含一个操作。操作1到3的格式为:"1 x y c" 或 "2 x y c" 或 "3 x y c"。操作4的格式为:"4 x y p"。

(其中,1 <= x <= y <= n,1 <= c <= 10,000,1 <= p <= 3)

输入以0 0结束。

输出:

对于每个操作4,输出一个整数作为结果,每个结果占一行。答案可能非常大,你只需计算答案除以10007的余数即可。

题目分析:

本题考查对lazy_tag标记的理解,有三种修改操作三种查询操作,意味着需要三种tag标记,我们分别定义为add[],multi[],change[]标记,需要知道的是他们在记录变化的时候,存在什么样的关系。

(1)做change修改时,原有的add和multi标记失效

(2)做multi修改时,如果原有add,则将add改为addmulti

(3)做线段树pushdown操作时,先处理change操作,后处理multi,最后执行add

三种查询操作,求和sum1,平方和sum2,立方和sum3。对于change和multi标记三种查询都很容易计算,对于add标记sum求和容易计算,但平方和与立方和需要推倒:

平方和sum2:

(a+c)2=a2+c
c+2ac,即sum2[new]=sum2[old]+(R-L+1)cc+2sum1[old]c

立方和

(a+c)3=a3+ccc+3c(a**2+ac),即sum3[new]=sum3[old]+(R-L+1)ccc+3c(sum2[old]+sum1[old]c)

注:公式还需要结合操作二

代码:

来自园内大佬

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
using namespace std;
const int MOD = 10007;
const int MAXN = 100010;
struct Node {
int l, r;
int sum1, sum2, sum3;
int lazy1, lazy2, lazy3;
} segTree[MAXN * 3];
void build(int i, int l, int r) {
segTree[i].l = l;
segTree[i].r = r;
segTree[i].sum1 = segTree[i].sum2 = segTree[i].sum3 = 0;
segTree[i].lazy1 = segTree[i].lazy3 = 0;
segTree[i].lazy2 = 1; //乘法标记为1
int mid = (l + r) / 2;
if (l == r)return;
build(i << 1, l, mid);
build((i << 1) | 1, mid + 1, r);
}
void push_up(int i) {
if (segTree[i].l == segTree[i].r)
return;
segTree[i].sum1 = (segTree[i << 1].sum1 + segTree[(i << 1) | 1].sum1) % MOD;
segTree[i].sum2 = (segTree[i << 1].sum2 + segTree[(i << 1) | 1].sum2) % MOD;
segTree[i].sum3 = (segTree[i << 1].sum3 + segTree[(i << 1) | 1].sum3) % MOD; } void push_down(int i) {
if (segTree[i].l == segTree[i].r) return;
if (segTree[i].lazy3 != 0) {
segTree[i << 1].lazy3 = segTree[(i << 1) | 1].lazy3 = segTree[i].lazy3;
//加标记改为0,乘标记改为1即可将标记清除,将原有的标记清除
segTree[i << 1].lazy1 = segTree[(i << 1) | 1].lazy1 = 0;
segTree[i << 1].lazy2 = segTree[(i << 1) | 1].lazy2 = 1;
//左孩子节点更新
segTree[i << 1].sum1 = (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i << 1].lazy3 % MOD; //c
segTree[i << 1].sum2 = (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i << 1].lazy3 % MOD * segTree[i << 1].lazy3 % MOD; //c*c
segTree[i << 1].sum3 = (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i << 1].lazy3 % MOD * segTree[i << 1].lazy3 % MOD * segTree[i << 1].lazy3 % MOD; //c*c*c
//右孩子节点更新
segTree[(i << 1) | 1].sum1 = (segTree[(i << 1) | 1].r - segTree[(i << 1) | 1].l + 1) * segTree[(i << 1) | 1].lazy3 % MOD;
segTree[(i << 1) | 1].sum2 = (segTree[(i << 1) | 1].r - segTree[(i << 1) | 1].l + 1) * segTree[(i << 1) | 1].lazy3 % MOD * segTree[(i << 1) | 1].lazy3 % MOD;
segTree[(i << 1) | 1].sum3 = (segTree[(i << 1) | 1].r - segTree[(i << 1) | 1].l + 1) * segTree[(i << 1) | 1].lazy3 % MOD * segTree[(i << 1) | 1].lazy3 % MOD * segTree[(i << 1) | 1].lazy3 % MOD;
//标记传递后需要删除
segTree[i].lazy3 = 0;
}
if (segTree[i].lazy1 != 0 || segTree[i].lazy2 != 1) {
int sum1, sum2, sum3;
//在做线段树pushdown操作时,先执行change,再执行multi,最后执行add //更新标记
segTree[i << 1].lazy1 = (segTree[i].lazy2 * segTree[i << 1].lazy1 % MOD + segTree[i].lazy1) % MOD;
segTree[i << 1].lazy2 = segTree[i << 1].lazy2 * segTree[i].lazy2 % MOD; //更新sum,在做线段树pushdown操作时,先执行change,再执行multi,最后执行add
sum1 = (segTree[i << 1].sum1 * segTree[i].lazy2 % MOD + (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i].lazy1 % MOD) % MOD;
sum2 = (segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i << 1].sum2 % MOD + 2 * segTree[i].lazy1 * segTree[i].lazy2 % MOD * segTree[i << 1].sum1 % MOD + (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
sum3 = segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i << 1].sum3 % MOD;
sum3 = (sum3 + 3 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i << 1].sum2) % MOD;
sum3 = (sum3 + 3 * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i << 1].sum1) % MOD;
sum3 = (sum3 + (segTree[i << 1].r - segTree[i << 1].l + 1) * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
segTree[i << 1].sum1 = sum1;
segTree[i << 1].sum2 = sum2;
segTree[i << 1].sum3 = sum3; segTree[i << 1 | 1].lazy1 = (segTree[i].lazy2 * segTree[i << 1 | 1].lazy1 % MOD + segTree[i].lazy1) % MOD;
segTree[i << 1 | 1].lazy2 = segTree[i << 1 | 1].lazy2 * segTree[i].lazy2 % MOD; sum1 = (segTree[i << 1 | 1].sum1 * segTree[i].lazy2 % MOD + (segTree[i << 1 | 1].r - segTree[i << 1 | 1].l + 1) * segTree[i].lazy1 % MOD) % MOD;
sum2 = (segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i << 1 | 1].sum2 % MOD + 2 * segTree[i].lazy1 * segTree[i].lazy2 % MOD * segTree[i << 1 | 1].sum1 % MOD + (segTree[i << 1 | 1].r - segTree[i << 1 | 1].l + 1) * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
sum3 = segTree[i].lazy2 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i << 1 | 1].sum3 % MOD;
sum3 = (sum3 + 3 * segTree[i].lazy2 % MOD * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i << 1 | 1].sum2) % MOD;
sum3 = (sum3 + 3 * segTree[i].lazy2 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i << 1 | 1].sum1) % MOD;
sum3 = (sum3 + (segTree[i << 1 | 1].r - segTree[i << 1 | 1].l + 1) * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD * segTree[i].lazy1 % MOD) % MOD;
segTree[i << 1 | 1].sum1 = sum1;
segTree[i << 1 | 1].sum2 = sum2;
segTree[i << 1 | 1].sum3 = sum3; //传递后需要清除标记
segTree[i].lazy1 = 0;
segTree[i].lazy2 = 1; }
}
void update(int i, int l, int r, int type, int c) {
if (segTree[i].l >= l && segTree[i].r <= r) {
//根据公式填写即可
c %= MOD;
if (type == 1) {
segTree[i].lazy1 += c;
segTree[i].lazy1 %= MOD;
segTree[i].sum3 = (segTree[i].sum3 + 3 * segTree[i].sum2 % MOD * c % MOD + 3 * segTree[i].sum1 % MOD * c % MOD * c % MOD + (segTree[i].r - segTree[i].l + 1) * c % MOD * c % MOD * c % MOD) % MOD;
segTree[i].sum2 = (segTree[i].sum2 + 2 * segTree[i].sum1 % MOD * c % MOD + (segTree[i].r - segTree[i].l + 1) * c % MOD * c % MOD) % MOD;
segTree[i].sum1 = (segTree[i].sum1 + (segTree[i].r - segTree[i].l + 1) * c % MOD) % MOD;
}
else if (type == 2) {
segTree[i].lazy1 = segTree[i].lazy1 * c % MOD;
segTree[i].lazy2 = segTree[i].lazy2 * c % MOD;
segTree[i].sum1 = segTree[i].sum1 * c % MOD;
segTree[i].sum2 = segTree[i].sum2 * c % MOD * c % MOD;
segTree[i].sum3 = segTree[i].sum3 * c % MOD * c % MOD * c % MOD;
}
else {
segTree[i].lazy1 = 0;
segTree[i].lazy2 = 1;
segTree[i].lazy3 = c % MOD;
segTree[i].sum1 = c * (segTree[i].r - segTree[i].l + 1) % MOD;
segTree[i].sum2 = c * (segTree[i].r - segTree[i].l + 1) % MOD * c % MOD;
segTree[i].sum3 = c * (segTree[i].r - segTree[i].l + 1) % MOD * c % MOD * c % MOD;
}
return;
}
push_down(i);
//二分
int mid = (segTree[i].l + segTree[i].r) / 2;
if (l <= mid)update(i << 1, l, r, type, c);
if (r > mid)update((i << 1) | 1, l, r, type, c);
push_up(i);
}
int query(int i, int l, int r, int p) {
if (segTree[i].l >= l && segTree[i].r <= r) {
if (p == 1)return segTree[i].sum1;
else if (p == 2)return segTree[i].sum2;
else return segTree[i].sum3;
}
push_down(i);
int mid = (segTree[i].l + segTree[i].r) / 2;
int sum = 0;
if (l <= mid) sum += query(i << 1, l, r, p);
if (r > mid) sum += query((i << 1) | 1, l, r, p);
return sum % MOD;
} int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n, m;
while (scanf("%d%d", &n, &m) == 2) {
if (n == 0 && m == 0)break;
build(1, 1, n);
int type, x, y, c;
while (m--) {
scanf("%d%d%d%d", &type, &x, &y, &c);
if (type == 4)printf("%d\n", query(1, x, y, c));
else update(1, x, y, type, c);
}
}
return 0;
}

线段树 transformation——hdu 4578的更多相关文章

  1. Transformation HDU - 4578(线段树——懒惰标记的妙用)

    Yuanfang is puzzled with the question below: There are n integers, a 1, a 2, …, a n. The initial val ...

  2. 【线段树】HDU 5493 Queue (2015 ACM/ICPC Asia Regional Hefei Online)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5493 题目大意: N个人,每个人有一个唯一的高度h,还有一个排名r,表示它前面或后面比它高的人的个数 ...

  3. 【线段树】HDU 5443 The Water Problem

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5443 题目大意: T组数据.n个值,m个询问,求区间l到r里的最大值.(n,m<=1000) ...

  4. 树链剖分处理+线段树解决问题 HDU 5029

    http://acm.split.hdu.edu.cn/showproblem.php?pid=5029 题意:n个点的树,m次操作.每次操作输入L,R,V,表示在[L,R]这个区间加上V这个数字.比 ...

  5. 【线段树】HDU 1166 敌兵布阵

    这道题目是线段树里面最基础的单点更新问题. 设计的知识点包括线段树的单点更新和区间查询. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 G++ ...

  6. 线段树扫描线 HDU 1542

    n个矩形 问他们覆盖的面积重复的就算一次 x数组存线段  然后根据横坐标排一下 z 线段树 l - r   就是1 ~ 2*n #include<stdio.h> #include< ...

  7. 线段树(hdu 1556)

    Problem Description: N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电 ...

  8. 线段树(hdu 2795)

    Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  9. 线段树(hdu 1754 i hate it)

    I Hate It Time Limit: 3000MS     Memory Limit: 32768 K Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分 ...

  10. 线段树模板hdu 1166:敌兵布阵

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

随机推荐

  1. [rCore学习笔记 08]内核第一条指令

    了解QEMU 启动指令 qemu-system-riscv64 \ -machine virt \ -nographic \ -bios ../bootloader/rustsbi-qemu.bin ...

  2. 基于Hive的大数据分析系统

    1.概述 在构建大数据分析系统的过程中,我们面对着海量.多源的数据挑战,如何有效地解决这些零散数据的分析问题一直是大数据领域研究的核心关注点.大数据分析处理平台作为应对这一挑战的利器,致力于整合当前主 ...

  3. 概括下为什么要用vue开发

    很多老程序员,习惯了使用原生html和js来开发前端页面,对于很多没用过vue的程序员来说,觉得没有必要. 下面,我来概括下vue的一些好处: 1.控件自动跟数据绑定,提交表单到后台的时候,可以直接使 ...

  4. 图解Java设计模式

    待补充 设计模式介绍 设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案. 设计模式使用的位置 功能模块+框架上. 设计模式在软件中哪里?面向对象( ...

  5. 计算机类的短周期的SCI期刊

    <Human-centric Computing and Information Sciences> 韩国人办的,Open Access,周期短,费用高,SCI二区,水毕业可用. 以下引自 ...

  6. 基于浅层神经网络(全连接网络)的强化学习算法(Reinforce) 在训练过程中出现梯度衰退(degenerate)的现象

    首先给出一个代码地址: https://gitee.com/devilmaycry812839668/CartPole-PolicyNetwork 强化学习中的策略网络算法.<TensorFlo ...

  7. Ubuntu Firefox浏览器播放视频报错,提示“需要安装所需的视频编码器”——解决方法:安装视频解码器

    给电脑重新做了一个Ubuntu的系统,安装系统的时候没有选择安装第三方软件,结果开机进系统打开firefox浏览器看个电影报错,提示"需要安装所需的视频编码器",效果如下: 解决方 ...

  8. 最新版gym-0.26.2下Atari环境的安装以及环境版本v0,v4,v5的说明

    强化学习的游戏仿真环境可以分为连续控制和非连续控制两类,其中连续控制的以mujoco为主,而非连续控制的以Atari游戏为主,本文对gym下的Atari环境的游戏环境版本进行一定的介绍. 参考:[转载 ...

  9. [CEOI2018] Lottery 题解

    前言 题目链接:洛谷. 题意简述 给出序列 \(a_1 \ldots a_n\) 和常数 \(l \leq n\),定义: \[\operatorname{dis}(i, j) = \sum _ {k ...

  10. 用户案例 | 蜀海供应链基于 Apache DolphinScheduler 的数据表血缘探索与跨大版本升级经验

    导读 蜀海供应链是集销售.研发.采购.生产.品保.仓储.运输.信息.金融为一体的餐饮供应链服务企业.2021年初,蜀海信息技术中心大数据技术研发团队开始测试用DolphinScheduler作为数据中 ...