zoukankan      html  css  js  c++  java
  • 【LOJ 6277】数列分块入门 1

    题目


    这是一道能用许多数据结构优化的经典题,可以用于不同数据结构训练。

    数列分块就是把数列中每(m)个元素打包起来,达到优化算法的目的。

    以此题为例,如果我们把每(m)个元素分为一块,共有(n/m)块,每次区间加的操作会涉及(O(n/m))个整块,以及区间两侧两个不完整的块中至多(2m)个元素。

    我们给每个块设置一个加法标记(就是记录这个块中元素一起加了多少),每次操作对每个整块直接(O(1))标记,而不完整的块由于元素比较少,暴力修改元素的值。

    每次询问时返回元素的值加上其所在块的加法标记。

    这样每次操作的复杂度是(O(n/m)+O(m)),根据均值不等式,当(m)(sqrt(n))时总复杂度最低。


    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=50005;
    int a[N],tag[N],L[N],R[N],pos[N];
    inline void add(int l,int r,int d) {
    	int p=pos[l],q=pos[r];
    	if(p==q) {
    		for(int i=l; i<=r; i++) {
    			a[i]+=d;
    		}
    	} else {
    		for(int i=p+1; i<q; i++) {
    			tag[i]+=d;
    		}
    		for(int i=l; i<=R[p]; i++) {
    			a[i]+=d;
    		}
    		for(int i=L[q]; i<=r; i++) {
    			a[i]+=d;
    		}
    	}
    }
    int main() {
    	int n;
    	scanf("%d",&n);
    	for(int i=1; i<=n; i++) {
    		scanf("%d",a+i);
    	}
    	int t=sqrt(n*1.0);
    	for(int i=1; i<=t; i++) {
    		L[i]=(i-1)*t+1,R[i]=i*t;
    	}
    	if(R[t]<n) {
    		t++,L[t]=R[t-1]+1,R[t]=n;
    	}
    	for(int i=1; i<=t; i++) {
    		for(int j=L[i]; j<=R[i]; j++) {
    			pos[j]=i;
    		}
    	}
    	for(int i=1,opt,l,r,c; i<=n; i++) {
    		scanf("%d %d %d %d",&opt,&l,&r,&c);
    		if(!opt) {
    			add(l,r,c);
    		} else {
    			printf("%d
    ",a[r]+tag[pos[r]]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    hdu 4614 线段树 二分
    cf 1066d 思维 二分
    lca 最大生成树 逆向思维 2018 徐州赛区网络预赛j
    rmq学习
    hdu 5692 dfs序 线段树
    dfs序介绍
    poj 3321 dfs序 树状数组 前向星
    cf 1060d 思维贪心
    【PAT甲级】1126 Eulerian Path (25分)
    【PAT甲级】1125 Chain the Ropes (25分)
  • 原文地址:https://www.cnblogs.com/Sam2007/p/13160031.html
Copyright © 2011-2022 走看看