线段树 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 ...
随机推荐
- 2个月搞定计算机二级C语言——真题(1)解析
1. 前言 大家好,我是梁国庆. 这段时间将持续发布计算机二级 C 语言真题的解析,想要同步练习,需要资源包的朋友可以跳转免费获取--<3个月搞定计算机二级C语言--准备工作>. 现在恐怕 ...
- Python常见错误及处理
1.ValueError 值错误,传递给函数的变量不符合函数预期类型.如下'python'是非数字无法转换为整数类型,故会报错ValueError 将a改为数字就不会报错了 2.NameError 变 ...
- Fidder响应数据SyntaxView乱码的处理方法
当Fidder查看响应数据"SyntaxView"出现乱码时,可以点击上方菜单栏的"Decode"按钮,等"Decode"出现蓝色边框后再重 ...
- SpringBoot整合Redis,并处理序列化反序列化问题
1.添加Redis依赖 在项目的pom.xml文件中添加Redis的依赖项.例如,可以使用spring-boot-starter-data-redis依赖项来引入Redis的支持. <depen ...
- 【MybatisPlus】 Field '主键' doesn't have a default value
使用MybatisPlus的 PoMapper执行Insert插入方法报错: 复原场景: 1.PO对象存在主键值(双主键) 2.表中数据为空 3.首次插入 这张表使用的是双主键,发现原因是因为PO设置 ...
- 强化学习中经典算法 —— reinforce算法 —— (进一步理解, 理论推导出的计算模型和实际应用中的计算模型的区别)
在奖励折扣率为1的情况下,既没有折扣的情况下,reinforce算法理论上可以写为: 但是在有折扣的情况下,reinforce算法理论上可以写为: 以上均为理论模型. ================ ...
- 一个专为量化投资开发的强化学习算法框架:ElegantRL
链接: https://github.com/AI4Finance-Foundation/ElegantRL 这是一个专为量化投资开发的强化学习算法框架. 相关论文: ElegantRL-Podrac ...
- 高校教编程是否应该将Python作为主语言
偶读一文:https://www.cnblogs.com/qing-gee/p/12941219.html 想到了这样的一个老问题,个人搞计算机软件开发.人工智能的时间已经十余年,虽然个人能力有限但是 ...
- YouTube上的很多时视频就是有问题的,还经常不允许评论,妥妥的双标网站
过多的事情不说了,这些个外国反华势力的网站真是无时无刻的不在视频中加私货,你想评论吧他还能判断你的个人价值观来预估你的评价倾向然后禁止你评价,十分的气人.要是立场不够坚定的人真的是很容易被带偏,像这种 ...
- vant 爬坑 (一)
vant 通过脚手架安装: # 安装 Vue Cli npm install -g @vue/cli # 创建一个项目 vue create hello-world # 创建完成后,可以通过命令打开图 ...