线段树 transformation——hdu 4578
问题描述:
给定一个数列,数列中所有元素都初始化为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+cc+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的更多相关文章
- Transformation HDU - 4578(线段树——懒惰标记的妙用)
Yuanfang is puzzled with the question below: There are n integers, a 1, a 2, …, a n. The initial val ...
- 【线段树】HDU 5493 Queue (2015 ACM/ICPC Asia Regional Hefei Online)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5493 题目大意: N个人,每个人有一个唯一的高度h,还有一个排名r,表示它前面或后面比它高的人的个数 ...
- 【线段树】HDU 5443 The Water Problem
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5443 题目大意: T组数据.n个值,m个询问,求区间l到r里的最大值.(n,m<=1000) ...
- 树链剖分处理+线段树解决问题 HDU 5029
http://acm.split.hdu.edu.cn/showproblem.php?pid=5029 题意:n个点的树,m次操作.每次操作输入L,R,V,表示在[L,R]这个区间加上V这个数字.比 ...
- 【线段树】HDU 1166 敌兵布阵
这道题目是线段树里面最基础的单点更新问题. 设计的知识点包括线段树的单点更新和区间查询. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 G++ ...
- 线段树扫描线 HDU 1542
n个矩形 问他们覆盖的面积重复的就算一次 x数组存线段 然后根据横坐标排一下 z 线段树 l - r 就是1 ~ 2*n #include<stdio.h> #include< ...
- 线段树(hdu 1556)
Problem Description: N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电 ...
- 线段树(hdu 2795)
Billboard Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- 线段树(hdu 1754 i hate it)
I Hate It Time Limit: 3000MS Memory Limit: 32768 K Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分 ...
- 线段树模板hdu 1166:敌兵布阵
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
随机推荐
- Python 结合opencv实现图片截取和拼接
实践环境 python 3.6.2 scikit-build-0.16.7 win10 opencv_python-4.5.4.60-cp36-cp36m-win_amd64.whl 下载地址: ht ...
- P10245 Swimming Pool题解
P10245 Swimming Pool 题意 给你四条边 \(abcd\),求这四条边是否可以组成梯形. 思路 这显然是一道简单的普通数学题. 判断是否能构成梯形只需看四条边是否能满足,上底减下底的 ...
- 那些血淋淋的教训——math
1. 方程的解要写 x= 2023.12.10 晚上周测填空题第 \(2\) 题,方程的解写成了 \(7\) 而不是 \(x=7\). 2. 分类讨论 选填的最后一题. 3. 去绝对值看清楚符号(某个 ...
- mybatis源码分析:Mapper接口是什么
在<mybatis源码分析:启动过程>中分析了mybatis的启动过程,mybatis的启动过程主要集中在解析其核心配置文件(mybatis-config.xml)上,把配置文件中的配置全 ...
- Android低功耗子系统的投票机制以及触发进入系统休眠的过程
从kernel角度看,系统是否进入休眠应该由内核来控制,因此Linux引入了 wakeup source以及autosleep机制 关于wakeup source的介绍,请参考: Wakeup Sou ...
- 对比python学julia(第一章)--(第二节)似曾相识燕归来
Julia和python一样,都是跨平台开源语言,而且都是动态语言,所以毫无疑问,需要运行时支撑.很简单,到官网去下载julia(https://julialang.org/downloads/).和 ...
- 代码随想录Day4
24.两两交换链表中的节点 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点.你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换). 示例 1: 输入:head = [1, ...
- 搞笑视频 —— 每天一乐 —— "齐老师妙~啊!"
视频地址: https://quanmin.baidu.com/v/7250265959743227122
- 【转载】 Python格式化字符串f-string概览
版权声明:本文为CSDN博主「sunxb10」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/sunxb10/a ...
- [rCore学习笔记 022]多道程序与分时任务
写在前面 本随笔是非常菜的菜鸡写的.如有问题请及时提出. 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 思考 ...