其他分享
首页 > 其他分享> > P2357 守墓人(分块)

P2357 守墓人(分块)

作者:互联网

传送门

算法分析

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\n",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\n",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\n",a[1]);
	}
	return 0;
}

标签:lazy,暴力,bel,分块,int,守墓,P2357,修改,maxn
来源: https://www.cnblogs.com/2004-08-20/p/13616326.html