问题描述:

给定一个数列,数列中所有元素都初始化为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. C# 对象复制三种方法效率对比——反射、序列化、表达式树

    1.需求 在代码中经常会遇到需要把对象复制一遍,或者把属性名相同的值复制一遍. 比如: public class Student { public int Id { get; set; } publi ...

  2. CF1915B Not Quite Latin Square 题解

    CF1915B 题意 给出一个 \(3\) 行 \(3\) 列的字符矩形,其中每行都有字符 ABC 各一个组成,现有一个字符未知,求出未知字符. 思路 就是说每个字符都应该出现 \(3\) 次,所以我 ...

  3. Telegram手机号码反查工具

    Telegram手机号码反查工具 项目地址:https://github.com/bellingcat/telegram-phone-number-checker v1.2.1版本 要求python的 ...

  4. 【郝斌C ST】01

    自学视频<郝斌C语言自学教程> 01 -  09: https://www.bilibili.com/video/BV1os411h77o 1.为什么学习C语言? - C的起源和发展 第一 ...

  5. 【Spring-Security】Re14 Oauth2协议P4 整合SSO单点登陆

    创建一个SSO单点登陆的客户端工程 需要的依赖和之前的项目基本一致: <?xml version="1.0" encoding="UTF-8"?> ...

  6. 【Mycat】01 概述

    什么是Mycat? 数据库中间件 中间件:是一类连接软件组件和应用的计算机软件,以便于软件各部件之间的沟通. 例子:Tomcat,web中间件. 数据库中间件:连接java应用程序和数据库 为什么要用 ...

  7. T800机器人图片 —— 强大的好莱坞电影工业,T800机器人模型也如此精细真实!

    视频地址: https://www.ixigua.com/6764744689003266571

  8. 通用人工智能的基石 —— 人工智能“新基建、关键基础设施”—— 3D游戏引擎

    相关: https://www.unrealengine.com/zh-CN/uses/simulation https://www.epicgames.com/site/zh-CN/careers/ ...

  9. 支持AMD GPU —— 如何运行docker环境下的Jax环境

    相关: 支持NVIDIA GPU -- 如何运行docker环境下的Jax环境 官方给出的安装主页: https://hub.docker.com/r/rocm/jax 安装命令: docker pu ...

  10. 微软的GitHub Copilot

    随着OpenAI的ChatGPT4 Turbo的发布,基于ChatGPT的Copilot也推出了最新版. ======================================= 帮助文档: h ...