当前位置: 首页 > news >正文

分块算法

分块算法,是一种十分巧妙的算法,将优美与暴力融为一体,可以解决很多的题目

例题

弹飞绵羊(BZOJ)
洛谷的

题目大意就是有一个链状的弹簧装置,每个装置能将在上面的物体向后弹一定距离直至出界,每次询问从一个位置出发弹飞次数或修改某位置弹飞距离

这道题原本是LCT入门题,接下来我们将会看到分块是如何简洁地处理这道题目的

分块

什么是分块?
分块将所有数据分为若干个块,维护块内信息,使得块内的查询是\(O(1)\)的,而总的询问就可以看做若干个块询问的总和

为了使时间复杂度均摊,我们将块的大小设为\(O(\sqrt{n})\)
这样一来每次查询最多遍历\(O(\sqrt{n})\)个块,每个块是\(O(1)\),总的就是\(O(\sqrt{n})\)
对于修改,由于我们维护的是块内信息,对于单个块的修改是\(O(\sqrt{n})\)的,若一次修改横跨若干个块,只需将完全覆盖的块打标记即可,每次最多需要修改两个块
总复杂度\(O(q\sqrt{n})\)

题解

对于这道题,我们将弹簧分块,对于每个弹簧维护其step[i]表示其弹几次出块,nxt[i]表示弹出块后到达的位置
对于每次查询,我们统计step[i],块间转移
对于每次修改,暴力在块内修改step[]和nxt[]即可

总的来说,分块算法是一种优雅的暴力,在代码复杂度和时间复杂度上,有一个很好的平衡

代码【比LCT短多了】:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 200005,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
    return out * flag;
}
int n,m,T;
int K[maxn],step[maxn],nxt[maxn],b[maxn];
void query(int u){
    int ans = 0;
    while (u){
        ans += step[u];
        u = nxt[u];
    }
    printf("%d\n",ans);
}
void modify(int u,int k){
    K[u] = k;
    for (int i = u; b[i] == b[u] && i; i--){
        if (i + K[i] > n) step[i] = 1,nxt[i] = 0;
        else if (b[i] != b[i + K[i]]) step[i] = 1,nxt[i] = i + K[i];
        else step[i] = step[i + K[i]] + 1,nxt[i] = nxt[i + K[i]];
    }
}
int main(){
    n = read();  T = (int)sqrt(n);
    for (int i = 1; i <= n; i++) K[i] = read(),b[i] = i / T;
    for (int i = n; i; i--){
        if (i + K[i] > n) step[i] = 1,nxt[i] = 0;
        else if (b[i] != b[i + K[i]]) step[i] = 1,nxt[i] = i + K[i];
        else step[i] = step[i + K[i]] + 1,nxt[i] = nxt[i + K[i]];
    }
    m = read(); int opt,u;
    while (m--){
        opt = read(); u = read() + 1;
        if (opt & 1) query(u);
        else modify(u,read());
    }
    return 0;
}

转载于:https://www.cnblogs.com/Mychael/p/8330427.html

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • jQuery设置div的自适应布局
  • face alignment---各种算法框架
  • jQuery与vue分别实现超级简单的绿色拖动验证码功能
  • ShardingJDBC不支持批量插入的一种解决办法
  • NFS服务的端口分配
  • PHP中new self()和new static()的区别探究
  • rsync工具介绍
  • ubuntu配置虚拟主机
  • 客户端传输数据的方式
  • Django+Nginx+uwsgi搭建自己的博客(三)
  • turtlebot3_waffle 之PC工作环境搭建过程记录
  • Flask 安装 快速入门
  • To the Max
  • mysql--------char 和 varchar 的区别
  • WMI应用(一个系统自带的测试WMI语句的工具)
  • @jsonView过滤属性
  • CentOS6 编译安装 redis-3.2.3
  • in typeof instanceof ===这些运算符有什么作用
  • java2019面试题北京
  • mysql常用命令汇总
  • sublime配置文件
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Unix命令
  • vue的全局变量和全局拦截请求器
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 今年的LC3大会没了?
  • 跨域
  • 事件委托的小应用
  • 小李飞刀:SQL题目刷起来!
  • 原生 js 实现移动端 Touch 滑动反弹
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • Java性能优化之JVM GC(垃圾回收机制)
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • # Redis 入门到精通(一)数据类型(4)
  • #Linux(make工具和makefile文件以及makefile语法)
  • #进阶:轻量级ORM框架Dapper的使用教程与原理详解
  • (vue)页面文件上传获取:action地址
  • (保姆级教程)Mysql中索引、触发器、存储过程、存储函数的概念、作用,以及如何使用索引、存储过程,代码操作演示
  • (附源码)c#+winform实现远程开机(广域网可用)
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (南京观海微电子)——示波器使用介绍
  • (三十五)大数据实战——Superset可视化平台搭建
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (四)c52学习之旅-流水LED灯
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • .NET Core 2.1路线图
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .Net插件开发开源框架
  • .NET业务框架的构建
  • .so文件(linux系统)
  • @require_PUTNameError: name ‘require_PUT‘ is not defined 解决方法
  • [000-01-011].第2节:持久层方案的对比