HDU 4027 Can you answer these queries? (线段树成段更新 && 开根操作 && 规律)
题意 : 给你N个数以及M个操作,操作分两类,第一种输入 "0 l r" 表示将区间[l,r]里的每个数都开根号。第二种输入"1 l r",表示查询区间[l,r]里所有数的和。
分析 : 不难想到用线段树,但是这里的线段树开根操作的更新很明显不能跟加减操作那样子通过Lazy Tag来实现,那么最笨的方法就是一直更新到叶子节点,不过这也就失去了线段树的高效性,每一次操作都更新到叶子节点的话会超时,此时来想想有没有什么规律可以减少操作的复杂度,细想就会发现在有限次的开根之后所有的数都会变成1,这里能给出的最大的数是263这个数被开根七次之后就会变成1,那么如果需要更新的某一段的值已经被开根了7次或7次以上那么就无需再向下更新,也就是每个叶子节点最多更新7次。普通的线段树操作就不叙述了,这里说说判断是否已经开根七次的方法。
①多开辟一个标记数组来记录开根信息,比如给区间(l, r)开根,那么就把被(l, r)包裹住的子区间对应的标记+1,同样的,如果下一次碰到某一个子区间的标记已经>=7了那么就直接return无需向下更新。
#include<bits/stdc++.h> #define LL long long #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; + ; LL sumv[maxn<<]; ]; int N, M; inline void build(int l, int r, int rt) { if(l == r){ scanf("%I64d", &sumv[rt]); return ; } ; build(lson); build(rson); sumv[rt] = sumv[rt<<] + sumv[rt<<|]; } inline void update(int L, int R, int l, int r, int rt) { ){///先判断是否是被查询区间包裹的子区间,再判断是否需要继续向下更新 sumv[rt] = r - l + ; return ; } if(L <= l && r <= R) sq[rt]++;///注意什么时候需要+1 if(l == r){ ///sq[rt]++ 之前因为逻辑疏忽,我在这里也+1操作了,WA了很多次静下来思考才发现 sumv[rt] = (LL)sqrt(sumv[rt]); return ; } ; if(L <= m) update(L, R, lson); if(R > m) update(L, R, rson); sumv[rt] = sumv[rt<<] + sumv[rt<<|]; } LL query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) return sumv[rt]; LL ret = ; ; if(L <= m) ret += query(L, R, lson); if(R > m) ret += query(L, R, rson); return ret; } int main(void) { ; while(~scanf("%d", &N)){ memset(sumv, , sizeof(sumv)); memset(sq, , sizeof(sq)); build(, N, ); scanf("%d", &M); printf("Case #%d:\n", Case++); while(M--){ int command, L, R; scanf("%d%d%d", &command, &L, &R); if(L > R) swap(L, R); , N, ); , N, )); } puts(""); } ; }
②实际上有个更简便的方法,就是最后被开7次根及以上的区间和都会变成区间长度,那么我们只要每一次都判断被(l, r)包裹住的子区间的和是否等于区间长度就能判断是否需要再继续更新下去了。
#include<bits/stdc++.h> #define LL long long #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; + ; LL sumv[maxn<<]; int N, M; inline void build(int l, int r, int rt) { if(l == r){ scanf("%I64d", &sumv[rt]); return ; } ; build(lson); build(rson); sumv[rt] = sumv[rt<<] + sumv[rt<<|]; } inline void update(int L, int R, int l, int r, int rt) { ) return ; if(l == r){ sumv[rt] = (LL)sqrt(sumv[rt]); return ; } ; if(L <= m) update(L, R, lson); if(R > m) update(L, R, rson); sumv[rt] = sumv[rt<<] + sumv[rt<<|]; } LL query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R){ return sumv[rt]; } LL ret = ; ; if(L <= m) ret += query(L, R, lson); if(R > m) ret += query(L, R, rson); return ret; } int main(void) { ; while(~scanf("%d", &N)){ memset(sumv, , sizeof(sumv)); build(, N, ); scanf("%d", &M); printf("Case #%d:\n", Case++); while(M--){ int command, L, R; scanf("%d%d%d", &command, &L, &R); if(L > R) swap(L, R); , N, ); , N, )); } puts(""); } ; }
瞎 :
①更新到叶子节点的操作实际无需在main里面使用一个for循环,只要将update里面赋值的语句将原来的if(L <= l && r <= R)改成if(l == r)即可
②以后遇到类似开根的削减操作,可以考虑被削减多次之后变成的固定值会不会是解题的一个突破口
③在实现想法的时候需要认真思考,逻辑千万不能乱,否则调试起来相当困难,比如第一种判断方法下自己就写错了很多次,这还不要紧,关键是会怀疑一些没有必要怀疑的地方,冷静分析最重要,如果真的已经很乱了,不妨将代码删除,再来一遍!
HDU 4027 Can you answer these queries? (线段树成段更新 && 开根操作 && 规律)的更多相关文章
- HDU 4027 Can you answer these queries?(线段树,区间更新,区间查询)
题目 线段树 简单题意: 区间(单点?)更新,区间求和 更新是区间内的数开根号并向下取整 这道题不用延迟操作 //注意: //1:查询时的区间端点可能前面的比后面的大: //2:优化:因为每次更新都 ...
- hdu 4027 Can you answer these queries? 线段树区间开根号,区间求和
Can you answer these queries? Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/sho ...
- HDU 4027 Can you answer these queries? (线段树区间修改查询)
描述 A lot of battleships of evil are arranged in a line before the battle. Our commander decides to u ...
- hdu 4027 Can you answer these queries? 线段树
线段树+剪枝优化!!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm> #includ ...
- hdu 4747【线段树-成段更新】.cpp
题意: 给出一个有n个数的数列,并定义mex(l, r)表示数列中第l个元素到第r个元素中第一个没有出现的最小非负整数. 求出这个数列中所有mex的值. 思路: 可以看出对于一个数列,mex(r, r ...
- HDU 3577 Fast Arrangement ( 线段树 成段更新 区间最值 区间最大覆盖次数 )
线段树成段更新+区间最值. 注意某人的乘车区间是[a, b-1],因为他在b站就下车了. #include <cstdio> #include <cstring> #inclu ...
- ACM: Copying Data 线段树-成段更新-解题报告
Copying Data Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description W ...
- POJ3468_A Simple Problem with Integers(线段树/成段更新)
解题报告 题意: 略 思路: 线段树成段更新,区间求和. #include <iostream> #include <cstring> #include <cstdio& ...
- Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)
题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题 ...
随机推荐
- lsb-realse
[root@localhost ~]# lsb_release -a -bash: lsb_release: command not found 解决方法:yum install redhat-lsb ...
- Python基础语法之常量与变量
一.变量的命名规则 只能以下划线,数字和字母组成,不可以是特殊字符: 不可以以数字开头: 关键字不可作为变量名: 变量名区分大小写: 要具有描述性: 二.常量 python中并没有关键字const,在 ...
- win10安装mysql时报错[MY-012576] [InnoDB] Unable to create temporary file; errno: 2
报错信息 解决: 在my.ini文件里面的 [mysqld]区段内加入: #自己指定的临时文件目录 tmpdir="临时目录" 添加好后初始化成功 接下来启动mysql服务的时候报 ...
- Python3 AES加解密(AES/ECB/PKCS5Padding)
class AesEncry(object): key = "wwwwwwwwwwwwwwww" # aes秘钥 def encrypt(self, data): data = j ...
- django2.0变动数据库设置外键报错
1.报错TypeError: __init__() missing 1 required positional argument: 'on_delete' django2.0以后创建数据库外键的时候必 ...
- Vue下简单分页及搜索功能
最近利用Vue和element ui仿写了个小页面,记一哈分页和搜索功能的简单实现. 首页 emmmm..... 搜索框输入..... 搜索完成 数据是直接写在这里面的: cardPhoto:[ ...
- java调用webservice接口 几种方法
webservice的 发布一般都是使用WSDL(web service descriptive language)文件的样式来发布的,在WSDL文件里面,包含这个webservice暴露在外面可供使 ...
- MySQL索引优化(索引单表优化案例)
1.单表查询优化 建表SQL CREATE TABLE IF NOT EXISTS `article` ( `id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUT ...
- Ubuntu 14.04 下的MAC OS X 主题安装
Ubuntu 14.04 下的MAC OS X 主题安装 安装 MAC OS X 主题会帮助你的 Ubuntu 14.04 看起来更像MAC OS X.在这里我们介绍的Macbuntu安装包包含了GT ...
- Linux学习--第一天--Unix 、 Linux 发展史,Linux应用领域
UNIX发展史 肯·汤姆森开发出linux. 肯·汤姆森的同事丹尼斯·里奇在1971年开发了C语言. 操作系统 公司 硬件平台 AIX IBM PowerPC HP-UX HP PA-RISC Sol ...