#6280. 数列分块入门 4 #6281. 数列分块入门 5

题目描述

给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,区间求和。

输入格式

第一行输入一个数字 n。

第二行输入 n 个数字,第 i 个数字为 ai?,以空格隔开。

接下来输入 n 行询问,每行输入四个数字 opt、l、r、c,以空格隔开。

若 opt=0,表示将位于 [l,r]的之间的数字都加 c。

若 opt=1,表示询问位于 [l,r]的所有数字的和 ?mod(c+1)。

输出格式

对于每次询问,输出一行一个数字表示答案。

样例

样例输入

4
1 2 2 3
0 1 3 1
1 1 4 4
0 1 2 2
1 1 2 4

样例输出

1
4思路:分块,不是整块的暴力加,整块的用sum[]数组维护整块的和。代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=5e4+10;
ll a[maxn],b[maxn],sum[maxn],pos[maxn],n,block;
ll ans;
void update(int l,int r,int c)//更新
{
    for(int i=l;i<=min(pos[l]*block,(ll)r);i++)//左边不完整的块暴力加,sum数组维护
    {
        sum[pos[i]]+=c;
        a[i]+=c;
    }
    if(pos[l]!=pos[r])
    {
        for(int i=(pos[r]-1)*block+1;i<=r;i++)//右边不完整的块暴力加,sum数组维护
        {
            sum[pos[i]]+=c;
            a[i]+=c;
        }
    }
    for(int i=pos[l]+1;i<=pos[r]-1;i++)//整块的b数组保存
        b[i]+=c;
} 

ll query(int l,int r,int mod)//查询
{
    ans=0;
    for(int i=l;i<=min(pos[l]*block,(ll)r);i++)//左边不完整的块,暴力加每个数
        ans+=a[i]+b[pos[l]];
    if(pos[l]!=pos[r])
    {
        for(int i=(pos[r]-1)*block+1;i<=r;i++)//右边不完整的块,暴力加每个数
            ans+=a[i]+b[pos[r]];
    }
    for(int i=pos[l]+1;i<=pos[r]-1;i++)//完整的块整块加
    {
        ans+=sum[i]+b[i]*block;
    }
    return ans%mod;
}

int main()
{
    scanf("%d",&n);
    memset(sum,0,sizeof(sum));
    block=sqrt(n);//块的大小
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pos[i]=(i-1)/block+1;
        sum[pos[i]]+=a[i];//sum数组维护整块的和
    }
    int opt,l,r,c;
    for(int i=0;i<n;i++)
    {
        scanf("%d%d%d%d",&opt,&l,&r,&c);
        if(opt==0)
            update(l,r,c);
        else if(opt==1)
            printf("%lld\n",query(l,r,c+1));
    }
    return 0;
}

第5题:

思路:这里有个小思维,因为数的大小小于2^31,最多开方5次就为1。所以我们做法和上面一样有sum数组维护整块的值,

计算整块的时候,用flag记录整组都为1的情况,如果全为1就加block(块的大小),不是就暴力加,不会超时的,因为最多5次开方

就全为1了,时间复杂度和上面的一样(5倍对时间复杂度没关系)

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define inf 0x3f3f3f
using namespace std;
typedef long long ll;
const int maxn=5e4+10;
ll a[maxn],pos[maxn],sum[maxn],flag[maxn],block,n;
//a数组存储数字,pos记录每个数在哪个块,sum维护整块的和,flag标记整块是否全为1,blocK块的大小。
void update(int l,int r)//更新
{
    for(int i=l;i<=min(pos[l]*block,(ll)r);i++)//左边不完整块,暴力加。
    {
        sum[pos[l]]-=a[i];
        a[i]=sqrt(a[i]);
        sum[pos[l]]+=a[i];//sum数组记得改动
    }
    if(pos[l]!=pos[r])//右边不完整块,暴力加。
    {
        for(int i=(pos[r]-1)*block+1;i<=r;i++)
        {
            sum[pos[r]]-=a[i];
            a[i]=sqrt(a[i]);
            sum[pos[r]]+=a[i];
        }
    }
    for(int i=pos[l]+1;i<=pos[r]-1;i++)//整块
    {
        if(flag[i])//全为1,直接跳过
            continue;
        else//不是全为1,暴力处理
        {
            flag[i]=1;//先假设全为1,后面如果不是改为0
            for(int j=(i-1)*block+1;j<=i*block;j++)
            {
                sum[i]-=a[j];
                a[j]=sqrt(a[j]);
                sum[i]+=a[j];
                if(a[j]!=1)//不是全为1
                    flag[i]=0;
            }
        }
    }
}

void solve(int l,int r)
{
    ll ans=0;
    for(int i=l;i<=min(pos[l]*block,(ll)r);i++)//左边不完整块,暴力加
        ans+=a[i];
    if(pos[l]!=pos[r])
    {
        for(int i=(pos[r]-1)*block+1;i<=r;i++)//右边不完整块,暴力加
            ans+=a[i];
    }
    for(int i=pos[l]+1;i<=pos[r]-1;i++)//完整块直接加,整块的和即可
        ans+=sum[i];
    printf("%lld\n",ans);
}
int main()
{
    scanf("%d",&n);
    block=sqrt(n);//块的大小
    memset(flag,0,sizeof(flag));
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pos[i]=(i-1)/block+1;
        sum[pos[i]]+=a[i];//每块的和
    }
    int opt,l,r,c;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&opt,&l,&r,&c);
        if(opt==0)
            update(l,r);
        else
            solve(l,r);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/xiongtao/p/9780262.html

时间: 2024-08-30 17:43:52

#6280. 数列分块入门 4 #6281. 数列分块入门 5的相关文章

【蓝桥杯】入门训练 Fibonacci数列

入门训练 Fibonacci数列 时间限制:1.0s   内存限制:256.0MB 问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少. 输入格式 输入包含一个整数n. 输出格式 输出一行,包含一个整数,表示Fn除以10007的余数. 说明:在本题中,答案是要求Fn除以10007的余数,因此我们只要能算出这个余数即可,而不需要先计算出Fn的准确值,再将计算的结果除以10007取余

蓝桥杯 入门训练 Fibonacci数列(Java)

@Author : qingdujun 入门训练 Fibonacci数列  : http://lx.lanqiao.org/problem.page?gpid=T4 import java.util.Scanner; /** * 蓝桥杯: 入门训练 Fibonacci数列 * @author qingdujun * */ public class Main { public static void main(String[] args) { int f1 = 1; int f2 = 1; int

入门训练 Fibonacci数列 (水题)

入门训练 Fibonacci数列 时间限制:1.0s   内存限制:256.0MB 问题描述 Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1. 当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少. 输入格式 输入包含一个整数n. 输出格式 输出一行,包含一个整数,表示Fn除以10007的余数. 说明:在本题中,答案是要求Fn除以10007的余数,因此我们只要能算出这个余数即可,而不需要先计算出Fn的准确值,再将计算的结果除以10007取余

【分块】【权值分块】bzoj1901 Zju2112 Dynamic Rankings

论某O(n*sqrt(n))的带修改区间k大值算法. 首先对序列分块,分成sqrt(n)块. 然后对权值分块,共维护sqrt(n)个权值分块,对于权值分块T[i],存储了序列分块的前i块的权值情况. 对于区间询问,需要获得区间中每个值出现的次数,然后按权值扫O(sqrt(n)),完整的部分我们可以通过权值分块差分(O(1))得到(比如Lb~Rb块就是T[Rb]-T[Lb-1]),零散的部分我们再维护一个额外的权值分块,累计上该值即可.O(sqrt(n)). 对于修改,直接在该位置之后的所有权值分

Maven入门指南 :Maven 快速入门及简单使用

Maven入门指南 :Maven 快速入门及简单使用 前言 Maven是一个Java语言编写的开源项目管理工具,是Apache软件基金会的顶级项目.主要用于项目构建,依赖管理,项目信息管理. maven项目在编译.测试.打包里,会需要从maven的中央仓库(即:maven组织公布在互联网上的一个站点,里面已经收录了目前绝大多数主流的jar包)下载jar包等文件, 如果使用代理服务器上网,需要配置代理服务器. 理解"仓库" 首次运行完mvn -version后,会在用户目录下创建一个.m

1.2 lucene入门程序环境搭建及入门代码

 lucene入门程序环境搭建及入门代码 1.1      需求 使用lucene完成对数据库中图书信息的索引和搜索功能. 1.2      环境准备 l  Jdk:1.7及以上 l  Lucene:4.10(从4.8版本以后,必须使用jdk1.7及以上) l  Ide:indigo l  数据库:mysql 5 1.3      工程搭建 l  Mysql驱动包 l  Analysis的包 l  Core包 l  QueryParser包 l  Junit包(非必须) 创建po类 1 publ

SVN入门-2分钟教你入门

学习SVN首先我们应该知道,SVN是什么? SVN(Subversion)是一个开源的版本控制系統. SVN管理核心是:集中式管理,看一下集中式管理的工作流程图: 很好理解了,SVN的核心是服务器(配置器),下面看看SVN的宏观了解: 上面应用的操作很简单,以上是SVN的简单的入门,SVN提供了一个平台,教会了我们合作,共享,大大提高了团队的共组效率,记录了每一步的成长,以及人人为我,我为人人的思想. SVN入门-2分钟教你入门

LOJ#6281. 数列分块入门 5

内存限制:256 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: hzwer 提交提交记录统计讨论 1 测试数据 题目描述 给出一个长为 nnn 的数列,以及 nnn 个操作,操作涉及区间开方,区间求和. 输入格式 第一行输入一个数字 nnn. 第二行输入 nnn 个数字,第 i 个数字为 aia_ia?i??,以空格隔开. 接下来输入 nnn 行询问,每行输入四个数字 opt\mathrm{opt}opt.lll.rrr.ccc,以空格隔开. 若 opt=

LOJ.6281.数列分块入门5(分块 区间开方)

题目链接 int内的数(也不非得是int)最多开方4.5次就变成1了,所以还不是1就暴力,是1就直接跳过. #include <cmath> #include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar() typedef long long LL; const int N=5e4+5; int n,size,bel[N],A[N],tm[N]; LL sum[N]