P2357 守墓人题解

 题目背景

在一个荒凉的墓地上,有一个令人尊敬的守墓人,他看守的墓地从来没有被盗过, 所以人们很放心的把自己的先人的墓安顿在他那。

守墓人能看好这片墓地是必然而不是偶然……

因为……守墓人懂风水 0.0

题目描述

他把墓地分为主要墓碑和次要墓碑, 主要墓碑只能有 1 个, 守墓人把他记为 1 号, 而次要墓碑有 n−1 个,守墓人将之编号为 2,3…n,所以构成了一个有 n 个墓碑的墓地。

而每个墓碑有一个初始的风水值,这些风水值决定了墓地的风水的好坏,所以守墓人需要经常来查询这些墓碑。

善于运用风水的守墓人,通过一次次逆天改命,使得自己拥有了无限寿命,没人知道他活了多久。这天,你幸运的拜访到了他,他要求你和他共同见证接下来几年他的战果,但不过他每次统计风水值之和都需要你来帮他计算,算错了他会要你命 QAQ

风水也不是不可变,除非遭遇特殊情况,已知在接下来的 2147483647 年里,会有 f 次灾难,守墓人会有几个操作:

  1. 将 [l,r] 这个区间所有的墓碑的风水值增加 k。

  2. 将主墓碑的风水值增加 k。

  3. 将主墓碑的风水值减少 k。

  4. 统计 [l,r] 这个区间所有的墓碑的风水值之和。

  5. 求主墓碑的风水值。

上面也说了,很多人会把先人的墓安居在这里,而且守墓人活了很多世纪→_→,墓碑的数量会多的你不敢相信= =

守墓人和善的邀请你帮他完成这些操作,要不然哪天你的旅馆爆炸了,天上下刀子……

为了活命,还是帮他吧。

输入格式

第一行,两个正整数 n,f 表示共有 n 块墓碑,并且在接下来的 2147483647年里,会有 f 次世界末日。

第二行,n 个正整数,表示第 i 块墓碑的风水值。

接下来 f 行,每行都会有一个针对世界末日的解决方案,如题所述,标记同题。

输出格式

输出会有若干行,对 4 和 5 的提问做出回答,每个回答输出一行。

输入输出样例

输入 #1复制

5 7
0 0 0 0 0
1 1 5 1
1 1 3 3
2 3
3 1
4 1 5
2 1
5

输出 #1复制

16
7

说明/提示

20% 的数据满足:1≤n≤100。

50% 的数据满足:1≤n≤6000。

100% 的数据满足:1≤n,f≤2×105,答案不超过 64 位整数。

思路

线段树模板,直接维护。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long n,m,a[10000007],siz[40000007],u,ll,rr;
long long te[40000007],lz[40000007],xx;
void alz(long long a1,long long v){
	te[a1]+=siz[a1]*v;
	lz[a1]+=v;
}//a1打标记值v
void dow(long long a1){
	alz(a1*2,lz[a1]);
	alz(a1*2+1,lz[a1]);
	lz[a1]=0;
}//a1下发标记至儿子
void bu(long long a1,long long l,long long r){
	siz[a1]=r-l+1;
	if(l==r){
		te[a1]=a[l];
		return ;
	}
	long long mid=(l+r)/2;
	bu(a1*2,l,mid);
	bu(a1*2+1,mid+1,r);
	te[a1]=te[a1*2]+te[a1*2+1];
	return ;
}//l~r建树节点a1
void ci(long long a1,long long l,long long r,long long x,long long y,long long v){
	if(l>=x&&r<=y){
		alz(a1,v);
		return ;
	}
	long long mid=(l+r)/2;
	dow(a1);
	if(x<=mid){
		ci(a1*2,l,mid,x,y,v);
	}
	if(mid+1<=y){
		ci(a1*2+1,mid+1,r,x,y,v);
	}
	te[a1]=te[a1*2]+te[a1*2+1];
	return ;
}//x~y区间加v至l~r区间a1点
long long co(long long a1,long long l,long long r,long long x,long long y){
	if(x<=l&&r<=y){
		return te[a1];
	}
	long long mid=(l+r)/2;
	long long dbdb=0;
	dow(a1);
	if(mid>=x){
		dbdb+=co(a1*2,l,mid,x,y);
	}
	if(mid+1<=y){
		dbdb+=co(a1*2+1,mid+1,r,x,y);
	}
	return dbdb;
}//x~y区间问至l~r区间a1点	
int main(){
	cin>>n>>m;
	for(long long i=1;i<=n;i++){
		cin>>a[i];
	}
	bu(1,1,n);
	for(long long i=1;i<=m;i++){
		cin>>u;
		if(u==1){
			cin>>ll>>rr>>xx;
			ci(1,1,n,ll,rr,xx);
		}
		else if(u==4){
			cin>>ll>>rr;
			cout<<co(1,1,n,ll,rr)<<endl;
		}
        else if(u==2){
            cin>>xx;
            ci(1,1,n,1,1,xx);
        }
        else if(u==3){
            cin>>xx;
            ci(1,1,n,1,1,-xx);            
        }
        else{
			cout<<co(1,1,n,1,1)<<endl;            
        }
	}
	return 0;
}

posted @ 2025-10-11 07:51  bz02_2023f2  阅读(17)  评论(0)    收藏  举报  来源