简单分块1

    技术2025-06-03  46

    数列分块1

    题目描述

    给出一个长为  的数列,以及 n个操作,操作涉及区间加法,单点查值。

    大家很容易会想到差分。但题目的单点查询是在线查询(修改操作和查询操作是穿插在一起的,立刻回答)而差分是离线的(全部打完标记后,再求前缀和。把所有修改操作全做完了,再全部回答)如果差分在线做的,复杂度很高,要不停求前缀和

     

    所以这就要用分块了!

    分块:优雅的暴力

    我们先把数列切成√n块,那每一块就是√n,一共是n块。a数组是原始数组,b数组是用来打标记的。

    分块口诀:大段维护,小段暴力。

    #include <bits/stdc++.h> using namespace std; typedef long long ll; ll read()//快读 { ll x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); } return x*f; } int n,blo; int v[50005],bl[50005],atag[50005]; void add(int a,int b,int c)//大段维护,小段暴力 { for(int i=a;i<=min(bl[a]*blo,b);i++)//左端点所在的右边界 bl[a]左端点所在的块号*块的大小 v[i]+=c;//暴力加法 if(bl[a]!=bl[b])//如果a块和b块不相同 for(int i=(bl[b]-1)*blo+1;i<=b;i++)//b所在的左端点到b v[i]+=c;//暴力加法 for(int i=bl[a]+1;i<=bl[b]-1;i++)//a、b之间的完整大块 atag[i]+=c;//打标记 } int main() { n=read(); blo=sqrt(n);//每一块大小√n for(int i=1;i<=n;i++) v[i]=read(); for(int i=1;i<=n;i++) bl[i]=(i-1)/blo+1;//元素属于哪一块 for(int i=1;i<=n;i++) { int f=read(),a=read(),b=read(),c=read();//一系列查询 a~b区间 if(f==0) add(a,b,c);//区间统一增加 if(f==1) printf("%d\n",v[b]+atag[bl[b]]);//单点查询 原来的值v[b]加上一系列打上的标记 } return 0; }

    写作不易,麻烦动手点个赞,再走,行不?

    Processed: 0.010, SQL: 9