13行代码AC oj4是怎么回事呢?13行代码AC oj4相信大家都很熟悉,但是13行代码AC oj4是怎么回事呢,下面就让小编带大家一起了解吧。
13行代码AC oj4,其实就是13行代码AC oj4,大家可能会很惊讶13行代码AC oj4怎么会13行代码AC oj4呢?但事实就是这样,小编也感到非常惊讶。
这就是关于13行代码AC oj4的事情了,大家有什么想法呢,欢迎在评论区告诉小编一起讨论哦!
清华大学电子工程系《数据与算法》课程在线评测系统作业第四题:上班摸鱼  算账的会计

(此博客会随着作者的理解加深而逐步修改)

闲话少说,先奉上代码:

#include<cstdio>
int a[200006],t[200006],n;
void add(int x,int k){for(;x<=n;x+=x&-x){t[x]+=k;}}
int sum(int x){int sum=0;for(;x;x-=x&-x)sum+=t[x];return sum;}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){scanf("%d",&a[i]);add(i,a[i]);}
for(int i=1;i<=2*n;i++){
int boo;scanf("%d",&boo);
if(boo==1){int x,k;scanf("%d%d",&x,&k);k-=sum(x)-sum(x-1);add(x,k);}
else{int x,y;scanf("%d%d",&x,&y);printf("%d\n",sum(y)-sum(x-1));}
}
}

这是一道典型的树状数组模板题。虽然oj提示要求用线段树解决,线段树的题解我会另写一篇博客发出来

原题:

在采用快读之前获得了180ms的坏成绩

首先声明,本人并无oi经验,只是树状数组初学者,正如著名acmer所说:“很多初学者肯定和我一样,只知晓 BIT 代码精炼,语法简明。对于原理好像了解,却又如雾里探花总感觉隔着些什么。
本人仅在此对与本题有关的树状数组做简要说明,请感兴趣的同学自行学习。

推荐阅读:树状数组(BIT)—— 一篇就够了 - Last_Whisper - 博客园 (cnblogs.com)(哇我和大佬用了同样的博客园主题耶)

用蛮力法完成区间修改与查询的复杂度分析

在学习数据结构之前,在那个不用担心tle的《程序设计基础》年代,我们大家对这道题自然是随手推闭眼写的,即建立一个数组存储各个值,然后用循环暴力方法修改和查询。假设数组长度为n,操作区间长度为m,操作数为k,那么完成这样一套操作的时间复杂度为O(k(n+m)),这自然是题目设计合理,样例难度递进,练习范围全面,提升效果最好的无系数算oj所不能容忍的。我们发现,k次操作的复杂度几乎是不可降低的,对于每一次操作,我们有必要将线性复杂度进一步优化。

树状数组的定义

顾名思义,树状数组是用数组模拟了树的功能。学过线段树的同学可能知道,对于一个区间修改问题,可以用一颗二叉树存储数据的和,从而实现快速修改的操作。

(图片来自网络)

大概原理如上图。通过建立这样一棵树,实现了对于区间部分和的存储。线段树也是解决区间问题的重要手段。
However,本题只要求我们进行单点修改+区间求和,因此我们可以在线段树的基础上更简化一步。
众所周知,和-加数=加数,因此在两个加数与和中,我们只存储其中的两个元素,就可以推出第三个。而在1中的暴力法,我们可以看做存储了两个加数,复杂度表现不佳。线段树则是完全存储了三个数据,在两个数组下标中存储三个数据,显然要进行递归建树等,代码难度较高,且常数较大。我对树状数组的理解是:只存储一个加数以及和,同时通过谨慎地选取,使得每个节点值都是一个特殊区间的和(加数自己的和也是和),再通过巧妙的运算降低复杂度。原理如图。

(图片来自网络)

如图所示:

c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4,c5=a5,c6=a5+a6,c7=a7,c8=a1+a2+a3+a4+a5+a6+a7+a8。这样便形成了一个树状数组。

树状数组的原理

观察上面的例子,我们发现:
对于每个树状数组(以下记作数组t)节点i,其值t[i] = a[i - 2k+1] + a[i - 2k+2] + ... + a[i],其中k为i的二进制中从最低位到高位连续零的长度。下面我们简要证明这一点:
通过前面的分析,我们知道,树状数组节点的选取就是将线段树的所有右儿子去掉取得的,如果我们定义一个量指代从叶子节点开始算起向上的树高度,由于每个右儿子对应一个“2”,也就是对应了一个二进制数位,我们不难发现,数字的二进制最低位到最高位零的长度(称为k)正好是这一高度。比如,对于节点6,其k值为1,它的第一个父节点为上一节点的右儿子,再向上一层则是左儿子。这样,树状数组的各个值我们就构造出来了。
(不难发现指我只能找规律发现,并不会用数学方法证明)
那么,树状数组如何实现区间求和呢?
首先思考从节点1到节点n的求和。我们从n开始入手,Sn=tn+(a1+...+a[n-2^k])。然后循环往复,令n=n-2^k,一直相加直到n<=0,就得到了所有节点的和。
现在的关键问题是,2^k我们仍然不方便求解啊,用循环的方法的话,最终的复杂度并不能得到保证。
而这,也是树状数组,或者说二进制数的神奇之一。
记lowbit(k)=2^k,则有lowbit(k)=i&(-i)。(i指的是元素下标,由上述定义,我们知道每个i都对应了一个k)下面给出简要证明:
我们设i这个数字的二进制表示中,r1,r2,.....rn数位的值为“1”,其余数位为“0”(定义最后一位为第0位),则有:i=2^r1+....+2^rn。
由上述定义可知,k是i的二进制表示中从最低位到最高位连续0的高度,因此有k=rn。
而由于负数是由补码表示的,对于(-i),我们知道,由于前面有rn位为0,取反后是1,再+1后让rn个1进位,又第rn+1位是1,取反后是0,进位后得到1,因此得到了第rn+1位是1,后面rn位都是0的数字,也就是说后rn+1位数字与原来数字按位与后的结果都为1,而对于大于rn+1数位的数,由于下面没有进位,因此取反后再按位与的结果都为0。因此最终结果就是在第rn+1位得到一个0。那自然有2^k=i(&-i)成立。
正所谓:“文章本天成,妙手偶得之”。我们不得不为二进制数的精妙而折服。

树状数组的建立,修改与查询。

此处只介绍本题用到的单点修改与区间查询。

树状数组的单点修改

建立树状数组同时也是修改树状数组的一部分。建立树状数组就是把树状数组各个值从0修改到需要值,因此,我们只需要了解如何进行树状数组的单点修改。

void add(int x,int k){for(;x<=n;x+=x&-x){t[x]+=k;}}

从前面的原理分析我们知道,修改一个节点的值,需要对其涉及到的所有值都进行修改。刚才我们在求解t[i]的表达式时,对于每个节点,减去其对应的lowbit得到它需要的作用域(也就是i-2^k+1到i),那么一直递归下去(令i=i-2^k),就可以推到节点1,那么反过来看,我们只要把当前节点一直循环加上lowbit,就可以反推出所有带有这个节点值的节点。

树状数组的区间查询

int sum(int x){int sum=0;for(;x;x-=x&-x)sum+=t[x];return sum;}

我们前面提到了求解1-n区间的和。容易得出,从m到n的求和是Sn-Sm。

彩蛋

某著名oier锐评13行代码:

容我再去优化

我用13行摆烂了你的oj4的更多相关文章

  1. 无情摆烂我竟是cv怪物第四周周末总结

    无情摆烂我竟是cv怪物第四周周末总结 函数重要参数补充 1.*args 星号代表接收未被位置形参接收的额外的位置实参,无论有多少位置实参*args都可以将它全部接受 def func(*args): ...

  2. 我用了13行代碼開發出来的PHP框架

    我只用13行代碼開發的PHP框架,如果您對框架不理解,不知道框架究竟幫您做了什麽事,可以下載此框架看一下, 另外如果您想開發自己的框架也可以由這個框架的思路進行擴展. 源碼下載地址:http://do ...

  3. 使用13行Python代码实现四则运算计算器函数

    原创的刷新行数记录的代码!!! 支持带小括号,支持多个连续+-号,如-7.9/(-1.2-++--99.3/-4.44)*---(2998.654+-+-+-(+1.3-7.654/(-1.36-99 ...

  4. C# 13行代码带你模拟登录QQ空间

    最近想做一个QQ空间点赞的小工具,于是晚上下班回来就开始分析PC版的QQ空间,打开Chrome,切换到Network,然后输入账号密码,然后点击登录... 然后,我曹....一堆请求就开始了....搞 ...

  5. 13行代碼開發出来的PHP框架[转]

    <?PHP /** PHP極簡框架 交流: QQ群: 223494678 http://7di.net 用法 http://URL http://URL/hello http://URL/sev ...

  6. 13行代码实现:Python实时视频采集(附源码)

    一.前言 本文是<人脸识别完整项目实战>系列博文第3部分:程序设计篇(Python版),第1节<Python实时视频采集程序设计>,本章内容系统介绍:基于Python+open ...

  7. CodeForces 摆烂寄录

    按订正顺序排序 现在是乱排的了 完整代码占版面 所以只放 AC 记录链接 Good Bye 2021: 2022 is NEAR 这场打得真拉/tuu A. 简单签到 开场就读错题,浪费 5min / ...

  8. 摆烂期的Android学习笔记一

    Android大致分为四层架构1.Linux内核层:提供各种硬件驱动,如显示驱动,音频驱动,相机驱 动,蓝牙驱动.... 2.系统运行库层:通过C/c++库为android地图提供支持 3.应用框架层 ...

  9. ASP.NET Core 中文文档 第三章 原理(13)管理应用程序状态

    原文:Managing Application State 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:高嵩 在 ASP.NET Core 中,有多种途径可以对应用程序的状态进行 ...

随机推荐

  1. 微信小程序开发快速入手

    1.在page中的修改数据的setData函数,需要传递的是一个对象. that.setData({ src: res.tempFilePath }) 2.在 onload 事件中,可以获取wx.na ...

  2. 我的python学习记_02

    流程控制 算术运算符: + 加(在字符串中拼接作用) - 减 * 乘 / 除 // 商 % 取余 ** 次幂 比较运算符: > 是否大于 >= 是否大于等于 < 是否小于 != 是否 ...

  3. Java/C++实现访问者模式---购物车

    在我们课堂上的"购物车"的例子中,增加一个新的访问者:打包员,负责对购物车中货物装包. 类图: Java代码: public interface Product { void ac ...

  4. Hadoop搭建高可用的HA集群

    一.工具准备 1.7台虚拟机(至少需要3台),本次搭建以7台为例,配好ip,关闭防火墙,修改主机名和IP的映射关系(/etc/hosts),关闭防火墙 2.安装JDK,配置环境变量 二.集群规划: 集 ...

  5. IDEA个人常用快捷键

    Ctrl+Z:撤销 Ctrl+Shift+Z:重做 Ctrl+X:剪贴 Ctrl+C:复制 Ctrl+V:粘贴 Ctrl+Y:删除当前行 Ctrl+D:复制当前行 Alt+向左箭头:返回上次光标位置 ...

  6. 在 MarkDown 中添加表格(例如:在 CSDN 中添加表格)

    内容 一.使用 Markdown 创建表格(例如:在 CSDN 中创建表格) 1. 表格格式 对齐方式 -: 设置内容和标题栏居右对齐: :- 设置内容和标题栏居左对齐: :-: 设置内容和标题栏居中 ...

  7. kali添加开机自启[亲测有效]

    kali添加开机自启 采用systemd的方法,kali默认是没有rc.local的,需要自己创建.本方法也适用于ubuntu 18.04 64bit 改写rc-local.service 文件 先从 ...

  8. 【Oracle】EXPDP和IMPDP数据泵进行导出导入的方法

    一.expdp/impdp和exp/imp 客户端工具 1.exp和imp是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用. 服务端工具 2.expdp和impdp是服务端的工具程序,他们 ...

  9. 在非k8s 环境下 的应用 使用 Dapr Sidekick for .NET

    在k8s 环境下,通过Operator 可以管理Dapr sidecar, 在虚拟机环境下,我们也是非常需要这样的一个管理组件,类似下图:在这张图片中,在上图左面,我们看到了"dapr.ex ...

  10. npm 报错This is probably not a problem with npm. There is likely additional logging output above.

    报错This is probably not a problem with npm. There is likely additional logging output above. 安装了一个插件后 ...