zoukankan      html  css  js  c++  java
  • P2357 守墓人(分块)

    传送门

    算法分析

    • 区间修改 区间查询 单点修改 单点查询 显然可以用线段树做
    • 但是我们用另外一种神奇的暴力把这个 2e5的题碾过就会很舒服
    • 分块是一种比较常见的思想 分块也就是分治 把一个大区间分成几个小区间计算
    • 我们可以把每(log_n) 个数划分成一组 如果区间修改了整个块的话 不用去挨个修改单点的值 而是直接改掉整个块的信息 然后用lazy记录一下修改操作
    • 如果并没有修改掉整个块 那么我们就可以暴力处理 因为如果没有覆盖整个块 则操作元素个数肯定小于(2*log_n) 那么暴力处理也不会有太大的时间损耗
    • 如果查询的时候 查询区间跨过了整个块 那么我们直接统计块的信息就可以了 如果并没有跨过整个块 那么我们也一样直接暴力处理 注意先把每个块的lazy先处理掉 复杂度一样不会太高
    • 然后预处理一下每个点所属于的块就好了 注意修改和查询时的lazy的修改以及一些细节 比如修改的区间左端点和右端点同属于一个块

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 10;
    typedef long long ll;
    int a[maxn];
    ll sum[maxn];
    int lazy[maxn];
    int bel[maxn];
    int size;
    
    void change(int l,int r,int k){//区间修改
    	if(bel[l] == bel[r]){ //暴力处理 l 和 r 在同一个块的情况
    		for(int i = l;i <= r;++i) a[i] += k,sum[bel[l]] += k;
    		return;
    	}
    	for(int i = l;i <= bel[l] * size;++i) a[i] += k,sum[bel[l]] += k; // 暴力处理左边
    	for(int i = r;i >= (bel[r] - 1) * size + 1;--i) a[i] += k,sum[bel[r]] += k; // 暴力处理右边
    	for(int i = bel[l] + 1;i <= bel[r] - 1;++i)	lazy[i] += k,sum[i] += size * k; // 处理中间的块(这些块一定是整个覆盖掉的)
    }
    
    void ask(int l,int r){
    	ll ans = 0;
    	if(lazy[bel[l]]) {//把左端点的块的lazy下放
    		for(int i = (bel[l] - 1) * size + 1;i <= bel[l] * size;++i) a[i] += lazy[bel[l]];
    		lazy[bel[l]] = 0;
    	}
    	if(lazy[bel[r]]) {//右端点的块的lazy下放
    		for(int i = bel[r] * size;i >= (bel[r] - 1) * size + 1;--i) a[i] += lazy[bel[r]];
    		lazy[bel[r]] = 0;
    	}
            //中间块的lazy没必要处理 因为我们只需要统计区间和 而lazy对块的sum是没有影响的
    	if(bel[l] == bel[r]) {//暴力处理左右端点属于同一个块的情况
    		for(int i = l;i <= r;++i) ans += a[i];
    		printf("%lld
    ",ans);
    		return;
    	}
    	for(int i = l;i <= bel[l] * size;++i) ans += a[i];//暴力处理左端点所属的块
    	for(int i = r;i >= (bel[r] - 1) * size + 1;--i) ans += a[i];//暴力处理右端点所属于的块
    	for(int i = bel[l] + 1;i <= bel[r] - 1;++i) ans += sum[i]; // 处理中间块
    	printf("%lld
    ",ans);
    }
    
    int main(){
    	int n,m;scanf("%d%d",&n,&m);
    	size = sqrt(n);
    	for(int i = 1;i <= n;++i){
    		bel[i] = (i - 1) / size + 1;
    		scanf("%d",&a[i]);
    		sum[bel[i]] += a[i];
    	}
    	for(int i = 1;i <= m;++i){
    		int flag;scanf("%d",&flag);
    		if(flag == 1) {int l,r,k; scanf("%d%d%d",&l,&r,&k); change(l,r,k);}
    		if(flag == 2) {int k;scanf("%d",&k); a[1] += k; sum[1] += k;}
    		if(flag == 3) {int k;scanf("%d",&k); a[1] -= k; sum[1] -= k;}
    		if(flag == 4) {int l,r; scanf("%d%d",&l,&r); ask(l,r);}
    		if(flag == 5) printf("%d
    ",a[1]);
    	}
    	return 0;
    }
    
    
    如初见 与初见
  • 相关阅读:
    hibernate的核心配置
    hibernate的映射配置
    数据库的维护
    索引
    数据库规范化设计
    数据控制DCL
    触发器
    SQL存储过程简介
    Transact-SQL简介
    sysdatabaes表与sysobjects表
  • 原文地址:https://www.cnblogs.com/HISKrrr/p/13616326.html
Copyright © 2011-2022 走看看