HDU - 4578 线段树+三重操作
这道题自己写了很久,还是没写出来,也看了很多题解,感觉多数还是看的迷迷糊糊,最后面看到一篇大佬的才感觉恍然大悟。
先上一篇大佬的题解:https://blog.csdn.net/aqa2037299560/article/details/82872866?tdsourcetag=s_pcqq_aiomsg (既简单又高效 代码还短!%%%)
先说下题意:
就是给你n个数,每个数的初始值都是为0
然后给你m个操作
每个操作有 4 个数 op x y c
当 op==1 的时候,把 x到y 范围内的数 都 加上 c
当 op==2 的时候,把 x到y 范围内的数 都 乘以 c
当 op==3 的时候,把 x到y 范围内的数 都 等于 c
当 op==4 的时候,把 x到y 范围内的 每一个数 的 c 次方的和 输出(注意,当op等于4的时候,c的范围为1~3)
下面说说思路:
关键就是在于这个 懒惰值的传递,和 区间的每一个值是否都相等的问题
一.先说说树的数据
这个大家参考下就可以,实现的方法有很多,不一定需要这么写,把这个先放上来是便于理解。(我这么写是因为我太菜了)
struct Data {
ll l, r, val;//分别是左边界,右边界,懒惰值(也是该区间每一个叶节点的值)
bool dif;//判断区间内每一个区间是否的相同
}tree[M << ];
二.再说这个区间值都相等
我们可以知道,如果区间内的每一个值都相等,那么我们只要 求 其中一个的值的c次方,然后把该数乘以(右边界 减去 左边界 再加 1 ),便是该区间值的次方总和了
如果该区间的每一个值不相等,那么我们必须接着向下探索,直到 找到 一个 区间内的每一个值都相等 的区间,最坏的情况也就是找到叶节点。
三.懒惰值的传递
如果这个区间的每一个值都相等,那么它的左右子区间肯定也都是相等的。
如果这个区间不是全等区间,那么我们就没必要传递懒惰值,因为你这个区间每一个值不一定相等 ; 但是如果是全等区间,就要传递懒惰值。
如果我们在更新数据的过程中,需要用到传递懒惰值,那么肯定是要修改这个区间的某一个子区间,所以传递后,这个区间肯定不会再是全等区间
四.数据的更新
我们在更新完值后,肯定也需要更新区间是否相等的信息
有三种情况:
1.如果该区间的左右子区间 都不是 全等区间的话,那这个区间肯定也 不是 全等区间
2.如果该区间的左右子区间 都是 全等区间, 但是它们的 叶节点的值都 不相等,那么这个区间肯定 也不是 全等区间
3.如果该区间的左右区间 都是 全等区间,并且 它们的 叶节点的值都 全等,那么这个区间 肯定是 全等区间
下面上代码:
#include <algorithm>
#include <iostream>
#include<sstream>
#include<iterator>
#include<cstring>
#include<string>
#include<cstdio>
#include<cctype>
#include<vector>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set> #define M 100005
#define mod 10007
#define inf 0x3f3f3f3f
#define left k<<1
#define right k<<1|1
#define ms(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std; struct Data {
ll l, r, val; // 分别是左边界,右边界,懒惰值(也是该区间每一个叶节点的值
bool dif;//判断区间内每一个区间是否的相同
}tree[M << ]; ll ans, temp;
ll op, c, p;
int x, y, n, m; void built(int l, int r, int k) {
tree[k].l = l, tree[k].r = r, tree[k].val = , tree[k].dif = true;//初始化,每一个区间肯定都是全等的
if (l == r)return;
int mid = (l + r) >> ;
built(l, mid, left);
built(mid + , r, right);
} void down(int k) {
if (tree[k].l == tree[k].r)return;//如果这个数就是子区间那么没必要往下传递了
tree[k].dif = false;//传递后可能不是全等区间了
tree[left].val = tree[right].val = tree[k].val;//传递懒惰值
tree[left].dif = tree[right].dif = true;//暂时都是全等区间
} void updata(int k) {
if (tree[k].l >= x && tree[k].r <= y && tree[k].dif) {//在要操作的区间范围内,并且是全等区间就可以直接操作
if (op == ) {//操作一,加上c
tree[k].val = (tree[k].val + c) % mod;
}
else if (op == ) {//操纵二,乘以c
tree[k].val = (tree[k].val * c) % mod;
}
else {//操作三,等于c
tree[k].val = c % mod;
}
return;
}
if (tree[k].dif)down(k);//如果该区间是全等区间,那么就要传递懒惰值,并且传递后该区间肯定是 不全等区间
int mid = (tree[k].l + tree[k].r) >> ; if (x <= mid)updata(left);
if (y > mid)updata(right);
//传递后三种情况分析更新
if (!tree[left].dif || !tree[right].dif)tree[k].dif = false;
else {
if (tree[left].val != tree[right].val)tree[k].dif = false;
else {
tree[k].dif = true;
tree[k].val = tree[left].val;
}
}
} void query(int k) {
if (tree[k].l >= x && tree[k].r <= y && tree[k].dif) {//如果是全等区间,那么每一个数的值都相等
temp = pow(tree[k].val, c);
temp *= (tree[k].r - tree[k].l + );
ans = (ans + temp) % mod;
return;
}
if (tree[k].dif)down(k);//如果该区间是全等区间,那么就要传递懒惰值,并且传递后该区间肯定是 ”全等区间“
int mid = (tree[k].l + tree[k].r) >> ;
if (x <= mid)query(left);
if (y > mid)query(right);
} int main() {
while (scanf("%d%d", &n, &m) != EOF && n && m) {
built(, n, );
for (int i = ; i <= m; i++) {
scanf("%d%d%d%d", &op, &x, &y, &c);
if (op == ) {
ans = ;
query();
cout << ans << endl;
}
else {
updata();
}
}
}
return ;
}
HDU - 4578 线段树+三重操作的更多相关文章
- hdu 4578 线段树(标记处理)
Transformation Time Limit: 15000/8000 MS (Java/Others) Memory Limit: 65535/65536 K (Java/Others) ...
- hdu 2871 线段树(各种操作)
Memory Control Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- HDU 4578 线段树玄学算法?
Transformation 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4578 Problem Description Yuanfang is p ...
- HDU 4578 线段树复杂题
题目大意: 题意:有一个序列,有四种操作: 1:区间[l,r]内的数全部加c. 2:区间[l,r]内的数全部乘c. 3:区间[l,r]内的数全部初始为c. 4:询问区间[l,r]内所有数的P次方之和. ...
- hdu 4578 线段树 ****
链接:点我 1
- K - Transformation HDU - 4578 线段树经典题(好题)
题意:区间 加 变成定值 乘 区间查询:和 平方和 立方和 思路:超级超级超级麻烦的一道题 设3个Lazy 标记分别为 change 改变mul乘 add加 优先度change>m ...
- hdu 3436 线段树 一顿操作
Queue-jumpers Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) To ...
- hdu 3974 线段树 将树弄到区间上
Assign the task Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- hdu 3397 线段树双标记
Sequence operation Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...
随机推荐
- Inheritance and the prototype chain 继承和 原型 链
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain Inherita ...
- mnist数据集tensorflow实现
TensorFlow——CNN实现MNIST手写体识别 2019年04月08日 21:46:19 星空Ice_ 阅读数 83 文章目录 TensorFlowCNN实现MNIST 1,数据集 2,回 ...
- EUI库 - 9 - 数据集合 - 数组集合
ArrayCollection 当数组内的数据被修改了(增删改),组件能有效的获知 myCollection.addEventListener(eui.CollectionEvent.COLLE ...
- C++编程学习(二) 数据
博主已经有一些基础了,所以写的东西可能是容易错的,或者以前没记住的,或者是对理解知识点有帮助的.因此如果有纯小白看到了这篇博文,不懂的地方请自行百度啦~ 另外,本系列所有内容的图片均来自于西北工业大学 ...
- cd oldpwd
常用方式 环境变量OLDPWD表示前一次的当前目录.刚登录系统之后,这个变量是没有设置的. 环境变量PWD表示当前目录. 环境变量CDPATH用来指定cd命令的搜索路径,类似于PATH,它也是用:分隔 ...
- Floyd--P1119 灾后重建
题目背景 B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响.但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车.换句话说,只有连接着两个重建完成的村庄的公路才能 ...
- UVALive 4043 转化最佳完美匹配
首先黑点和白点是组成一个二分图这毫无疑问 关键是题目中要求的所有黑白配的线不能交叉...一开始我也没想到这个怎么转化为二分图里面的算法. 后来看书才知道,如果两两交叉,则可以把两根线当四边形的对角线, ...
- 【数据结构】C++语言环形队列的实现
队列--先进先出 队列的一个缺点--出队后的内存空间浪费了,不能二次利用 环形队列--解决以上缺点的队列,用过的内存空间可以重复利用 github: https://github.com/HITFis ...
- 2020/2/3 PHP代码审计之PHP伪协议
0x00 简介 开局一张图233 0x01 file://协议 说明: file:// 文件系统是 PHP 使用的默认封装协议,展现了本地文件系统.当指定了一个相对路径(不以/..\或 Windows ...
- HDU 5423:Rikka with Tree Dijkstra算法
Rikka with Tree Accepts: 207 Submissions: 815 Time Limit: 2000/1000 MS (Java/Others) Memory Limi ...