首页 > 其他分享 >分块——优雅的暴力

分块——优雅的暴力

时间:2024-06-04 23:34:09浏览次数:27  
标签:le 暴力 分块 int Sr 样例 优雅 区间 id

下面介绍一种暴力,当然呢这种暴力比一般快很多。
先说一下这个暴力的思路。对于一个长度为\(n\)的数组\(a\),可以把数组\(a\)分成\(k\)块,其中每一块的长度为\(len\),当然最后一行除外因为\(n\)可能不是\(k\)的倍数,最后一块的长度可以不是\(len\)。
那么就可以用这些块来维护数据。
那么对于一个区间\([l..r]\)可以分成两种情况:
\(1\).区间\([l..r]\)在同一个块里也就是:
image
这种情况下可以暴力枚举\(l\)到\(r\)即可。
\(2\).区间\([l..r]\)不在同一个块里也就是:、
image
这种情况下首先应该考虑中间整块的部分(图中\(3,4f\)),然后就是\(l\)和\(r\)中的残块也就是\(2\)和\(5\)中间的那一部分。

例题I 线段树1

点击查看题面 ## 题目描述

如题,已知一个数列,你需要进行下面两种操作:

  1. 将某区间每一个数加上 \(k\)。
  2. 求出某区间每一个数的和。

输入格式

第一行包含两个整数 \(n, m\),分别表示该数列数字的个数和操作的总个数。

第二行包含 \(n\) 个用空格分隔的整数,其中第 \(i\) 个数字表示数列第 \(i\) 项的初始值。

接下来 \(m\) 行每行包含 \(3\) 或 \(4\) 个整数,表示一个操作,具体如下:

  1. 1 x y k:将区间 \([x, y]\) 内每个数加上 \(k\)。
  2. 2 x y:输出区间 \([x, y]\) 内每个数的和。

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

样例 #1

样例输入 #1

5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

样例输出 #1

11
8
20

提示

对于 \(30\%\) 的数据:\(n \le 8\),\(m \le 10\)。
对于 \(70\%\) 的数据:\(n \le {10}^3\),\(m \le {10}^4\)。
对于 \(100\%\) 的数据:\(1 \le n, m \le {10}^5\)。

保证任意时刻数列中所有元素的绝对值之和 \(\le {10}^{18}\)。

【样例解释】

现在这一题是要支持区间求和,很显然用分块来维护区间和,那么可以用一个数组\(s\)表示当前块的最大和。
对于每一次的询问仍旧分为两部分\(l\)和\(r\)在同一块里和\(l\)和\(r\)不在同一块里。
那么代码就是:

int query(int l,int r){
    int sid=id[l],eid=id[r];//表示开始块编号和结束块编号
    if(sid==eid){//l,r在同一块里
        int sum=0;
        for(int i=l;i<=r;i++)sum+=a[i]+b[sid];//这里的a是原数组,b是每一块的懒标记
        return sum;
    }
    int sum=0;
    for(int i=l;id[i]==sid;i++)sum+=a[i]+b[sid];//l所对应的残块
    for(int i=sid+1;i<eid;i++)sum+=s[i];//l,r中间的真快,s是每一块的和
    for(int i=r;id[i]==eid;i--)sum+=a[i]+b[eid];//r所对应的残块
    return sum;
}

修改的方法和询问是一样的

void add(int l,int r,int x){
	int sid=id[l],eid=id[r];
	if(sid==eid){
		for(int i = l;i <= r;i ++ )s[sid] += x,a[i] += x;
		return;
	}
	for(int i = l;id[i] == id[l];i ++ ) s[id[l]] +=x,a[i] +=x;
	for(int i = sid + 1;i < eid;i ++ )s[i] += len * x,b[i] += x;
	for(int i = r;id[i] == id[r];i -- ) s[id[r]] +=x, a[i] += x;
}

完整代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;
int a[N],b[N],s[N];
int id[N];
int n,m,len;
int query(int l,int r){
    int sid=id[l],eid=id[r];
    if(sid==eid){
        int sum=0;
        for(int i=l;i<=r;i++)sum+=a[i]+b[sid];
        return sum;
    }
    int sum=0;
    for(int i=l;id[i]==sid;i++)sum+=a[i]+b[sid];
    for(int i=sid+1;i<eid;i++)sum+=s[i];
    for(int i=r;id[i]==eid;i--)sum+=a[i]+b[eid];
    return sum;
}
void add(int l,int r,int x){
    int sid=id[l],eid=id[r];
    if(sid==eid){
        for(int i = l;i <= r;i ++ ){
            s[sid] += x;
            a[i] += x;
        }
        return;
    }
    for(int i = l;id[i] == id[l];i ++ ) s[id[l]] +=x,a[i] +=x;
    for(int i = r;id[i] == id[r];i -- ) s[id[r]] +=x, a[i] += x;
    for(int i = sid + 1;i < eid;i ++ ){
        s[i] += len * x;
        b[i] += x;
    }
}
signed main(){
    cin>>n>>m;
    len=sqrt(n);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        int cnt=(i-1)/len+1;
        id[i]=cnt;
        s[cnt]+=a[i];
    }
    while(m--){
        int ops,l,r,c;cin>>ops>>l>>r;
        if(ops==1)cin>>c,add(l,r,c);
        else cout<<query(l,r)<<'\n';
    }
    return 0;
}

例题II

点击查看题面 # Anton and Permutation

题面描述

有一个长度为 \(n\) 的排列,初始为 \(1,2,\dots,n\)。

现在对其进行 \(k\) 次操作,每次操作都是交换序列中的某两个数。对于每一个操作,回答当前序列中有多少个逆序对。

样例 #1

样例输入 #1

5 4
4 5
2 4
2 5
2 2

样例输出 #1

1
4
3
3

样例 #2

样例输入 #2

2 1
2 1

样例输出 #2

1

样例 #3

样例输入 #3

6 7
1 4
3 5
2 3
3 3
3 6
2 1
5 1

样例输出 #3

5
6
7
7
10
11
8
首先可以先把分块数组逆序对的个数初始化为$0$ 每次交换a[l]与a[r],对序列的逆序对个数影响有多大?我们设[l+1,r-1]区间内比 a[l]小的元素有Sl个,比a[l]大的有Bl个,比a[r]小的元素有Sr个,比a[r]大的有Br个。 则逆序对的个数ans+=(Bl-Sl)+(Sr-Br)=(r-l-1-2*Sl)+(Sr-(r-l-1-Sr))=2*(Sr-Sl) 也就是说,每次给出询问[l,r],我们需要求出[l+1,r-1]区间内的Sl和Sr 另外,还需要单独判断一下a[l]和a[r]的大小关系,若a[l]

标签:le,暴力,分块,int,Sr,样例,优雅,区间,id
From: https://www.cnblogs.com/williamYcY/p/18231997

相关文章

  • 面试官:说一说如何优雅的关闭线程池,我:shutdownNow,面试官:粗鲁!
    优雅的关闭线程池我们现在步入正题,来看一看在线程池使用完成后如何优雅的关闭线程池。在JDK1.8中,Java并发工具包中java.util.concurrent.ExecutorService提供了shutdown()、shutdownNow()这两种接口方法去关闭线程池,我们分别看一下。shutdown()publicvoidshutdo......
  • 面试官:说一说如何优雅的关闭线程池,我:shutdownNow,面试官:粗鲁!
    写在开头面试官:“小伙子,线程池使用过吗,来聊一聊它吧!”我:“好的,然后巴拉巴拉一顿输出之前看过的build哥线程池十八问…”面试官满意的点了点头,紧接着问道:“那你知道如何优雅的关闭线程池吗?”我:“知道知道,直接调用shutdownNow()方法就好了呀!”面试官脸色一变,微怒道:“粗......
  • 面试官:说一说如何优雅的关闭线程池,我:shutdownNow,面试官:粗鲁!
    写在开头面试官:“小伙子,线程池使用过吗,来聊一聊它吧!”我:“好的,然后巴拉巴拉一顿输出之前看过的build哥线程池十八问...”面试官满意的点了点头,紧接着问道:“那你知道如何优雅的关闭线程池吗?”我:“知道知道,直接调用shutdownNow()方法就好了呀!”面试官脸色一变,微怒道:“粗鲁!你给......
  • 安防监控视频平台LntonCVS视频监控汇聚平台遏制校园暴力保护校园学生安全应用方案
    未成年人被誉为祖国的花朵,是我们国家的未来。然而,最近频繁曝出的未成年霸凌事件却引发了社会的广泛关注。这些事件手段残忍,事态恶劣,引发了全社会对如何保护未成年身心健康、规避霸凌事件发生的深刻思考。为了更好地保障学生的安全,许多学校开始引入基于“AI+视频”技术的人工......
  • 安防监控视频平台LntonCVS视频监控汇聚平台遏制校园暴力保护校园学生安全应用方案
    未成年人被誉为祖国的花朵,是我们国家的未来。然而,最近频繁曝出的未成年霸凌事件却引发了社会的广泛关注。这些事件手段残忍,事态恶劣,引发了全社会对如何保护未成年身心健康、规避霸凌事件发生的深刻思考。为了更好地保障学生的安全,许多学校开始引入基于“AI+视频”技术的人工......
  • 安装fail2ban服务-防止用户暴力破解root密码
    安装fail2ban服务,防止用户暴力破解root密码(最多让试着登录5次,5次密码输错就封杀ip)[root@bogon~]#lsepel-release-6-8.noarch.rpm[root@bogon~]#rpm-ivhepel-release-6-8.noarch.rpm #或yum-yinstallepel-release[root@bogon~]#yuminstallfail2ban-y复制ja......
  • 推荐一个小而全的 Java 工具类库,再也不用重复造轮子,简直太优雅(带私活源码)
    上周接到老大的需求说让整理下工具类,新项目要用,本想直接拿以前的改改直接用的,结果发现以前的工具类存在很多问题,光加解密工具类就重复写了很多个。赶紧跑去找有经验的同事商量对策,最终在Github上找到Hutool这款神器。简介Hutool是一个小而全的Java工具类库,通过静态......
  • 线程简述:协程、抢占式、sleep、wait、interrupt,优雅中断线程,线程通信等
    思维导图在此:java线程简述-CSDN博客1、线程与协程协程-->线程-->进程,协程最小协程:用户态,go语言线程:用户态、内核态都有。cpu调度的最小单位。是工人,从进程获取资源,多个线程共享进程的资源。进程:内核态。操作系统调度资源的最小单位。是资源管家。2、调度机制协同式。......
  • 三角网分块问题
        针对超大数据的构网问题,目前可行的方法就是对三角网进行分块处理,但是三角网的分块显然不像点云数据那么简单,如何对三角网进行切分,以及切分后块与块之间索引关系的建立都是难点;例如下图仅仅是对三角网进行了空间的切分,但是块与块的边界处的联系并没有建立。当然三角网......
  • ts拯救前端:优雅的在运行时校验后端接口返回数据类型 typescript-json-schema+ ajv
    包管理器:pnpm环境:node依赖:typescript-json-schema、ajv准备工作1、安装依赖pnpmaddtypescript-json-schemapnpmaddajv2、准备需要校验的数据类型//userType.tsexportinterfaceUser{id:string;token:string;nick?:string;}3、使用typescrip......