问题描述:

给定一个数列,数列中所有元素都初始化为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. 学习笔记--Java中final关键字

    Java中final关键字 关于Java语言中的final关键字: final是一个关键字,表示:最终的,不可改变 final修饰的类无法被继承 final修饰的方法无法被覆盖 final修饰的变量一 ...

  2. AS上的基础中级控件-图形定制

    图形Drawable 1.Drawable表达包含了图片色块画布背景等 2.存在res中的Drawable目录下,保存描述性的XML文件 3.各种视图都可以使用该控件如ViewText,Button, ...

  3. Jmeter函数助手21-evalVar

    evalVar函数用于执行变量表达式. 变量的名称:填入变量的名称name.注意不是引用变量${name} 1.evalVar函数和eval函数的区别:evalVar只能接收变量名称:eval能接收引 ...

  4. 【JavaScript】下滑线命名转驼峰命名处理

    同事写接口返回的JSON属性名称始终不一致,一会下划线一会驼峰 然后自己封装了一个: function toHump(name){ var newName = name.toLowerCase(); ...

  5. 【Dos-BatchPrograming】04

    --1.PING 主机联通性检测 Microsoft Windows [版本 10.0.19041.746] (c) 2020 Microsoft Corporation. 保留所有权利. C:\Us ...

  6. 【C】Re10 共用体、枚举、类型定义

    Union 联合体\共用体 结合体: 每个成员的内存空间都是独立存在的,互不干涉 int 成员.double 成员.char 成员 = 4 + 8 + 1 [13字节大小] 取成员字节占用之和作为这个 ...

  7. 【Vue】Re18 Router 第五部分(KeepAlive)

    一.KeepAlive概述 默认状态下,用户点击新的路由时,是访问新的组件 那么当前组件是会被销毁的,然后创建新的组件对象出来 如果某些组件频繁的使用,将造成内存空间浪费,也吃内存性能 所以需求是希望 ...

  8. 跨平台字幕制作软件ARCTIME

      官网:http://arctime.cn/

  9. 【转载】 新版 Kite为啥这么火,问就俩字『好用』

    本文转自: https://blog.csdn.net/qq_28168421/article/details/102927311 ---------------------------------- ...

  10. github的域名解析IP的文件——最直观的效果是GitHub图片可以正常加载,网页也稳定了——github图片不显示问题

    该codebase提供了hosts文件: https://github.com/ineo6/hosts 主站: https://github.com/ineo6/hosts 镜像: https://g ...