• LOJ 6277:数列分块入门 1(分块入门)


    #6277. 数列分块入门 1

    内存限制:256 MiB时间限制:100 ms标准输入输出

    题目类型:传统评测方式:文本比较

    上传者: hzwer

    提交提交记录统计讨论

    3

    测试数据

    题目描述

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

    输入格式

    第一行输入一个数字 n。

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

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

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

    若 opt=1,表示询问 ar 的值(l 和 c 忽略)。

    输出格式

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

    样例

    样例输入

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

    样例输出

    2
    5

    数据范围与提示

    对于100% 的数据,1≤n≤50000,−2^31≤others 、ans≤2^31−1。

    思路

    有好多种写法,因为在学分块,就用分块来写了

    将长度为n的数组进行分块,每个块的长度len=sqrt(n),块数为n/len

    每次需要更新时,判断需要更新的区间的左右端点是不是在一个块内,如果在一个块内,直接对这个区间进行更新就好了

    如果不在一个块内,从左端点开始到左端点所在的块的最后一个元素进行数组元素的更新,然后从右端点所在块的第一个元素开始到右端点进行数组元素的更新,对于中间的那些块,用tag数组记录下这个块中的元素一共加了多少

    最后输出的时候输出当前元素的值加上该元素所在块的tag值就行了

    AC代码

    /*
    * @Author: WZY
    * @School: HPU
    * @Date:   2018-10-11 17:08:19
    * @Last Modified by:   WZY
    * @Last Modified time: 2018-10-11 19:32:23
    */
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #include <limits.h>
    #include <map>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <set>
    #include <string>
    #include <time.h>
    #define ll long long
    #define ull unsigned long long
    #define ms(a,b) memset(a,b,sizeof(a))
    #define pi acos(-1.0)
    #define INF 0x7f7f7f7f
    #define lson o<<1
    #define rson o<<1|1
    #define bug cout<<"---------"<<endl
    #define debug(...) cerr<<"["<<#__VA_ARGS__"= "<<(__VA_ARGS__)<<" ]"<<"
    "
    const double E=exp(1);
    const int maxn=1e6+10;
    const int mod=1e9+7;
    using namespace std;
    int a[maxn];
    int blo[maxn];
    int tag[maxn];
    int block;
    inline void add(int l,int r,int c)
    {
    	// 对端点l到端点l所在块的终点进行操作
    	for(int i=l;i<=min(blo[l]*block,r);i++)
    		a[i]+=c;
    	// 如果左右端点不在一个块内,从右端点所在的块的起点到右端点进行操作
    	if(blo[l]!=blo[r])
    		for(int i=(blo[r]-1)*block+1;i<=r;i++)
    			a[i]+=c;
    	// 对中间的块用tag数组标记每个块内元素增加了多少
    	for(int i=blo[l]+1;i<=blo[r]-1;i++)
    		tag[i]+=c;
    }
    int main(int argc, char const *argv[])
    { 
    	ios::sync_with_stdio(false);
    	#ifndef ONLINE_JUDGE
    	    freopen("in.txt", "r", stdin);
    	    freopen("out.txt", "w", stdout);
    	    double _begin_time = clock();
    	#endif
    	int n;
    	int opt,l,r,c;
    	cin>>n;
    	// 每个块的长度为sqrt(n)
    	block=sqrt(n);
    	for(int i=1;i<=n;i++)
    		cin>>a[i];
    	// 计算下标1~n属于哪个块
    	for(int i=1;i<=n;i++)
    		blo[i]=(i-1)/block+1;
    	for(int i=1;i<=n;i++)
    	{
    		cin>>opt>>l>>r>>c;
    		if(opt)
    			cout<<a[r]+tag[blo[r]]<<endl;
    		else
    			add(l,r,c);
    	}
    	#ifndef ONLINE_JUDGE
    	    double _end_time = clock();
    	    printf("time = %lf ms.", _end_time - _begin_time);
    	#endif
    	return 0;
    }
  • 相关阅读:
    信协第一学期考核
    20175323《Java程序设计》第五周学习总结
    20175323《Java程序设计》第四周学习总结
    20175323《Java程序设计》第三周学习总结
    20175323《Java程序设计》第二周学习总结
    20175323 第一周学习总结
    第一次个人编程作业
    第一次博客作业
    团队项目-选题报告
    第一次结对编程作业
  • 原文地址:https://www.cnblogs.com/Friends-A/p/10324342.html
Copyright © 2020-2023  润新知