蒟蒻求助,全WA,关于思路有自己的注释,根《深入浅出》学的
查看原帖
蒟蒻求助,全WA,关于思路有自己的注释,根《深入浅出》学的
901562
ysq20110325楼主2023/7/17 20:51
#include<bits/stdc++.h>
using namespace std;
int n,m;
long long a[1111111],w[4111111],lzy[4111111];
//n—点的个数
//m—边的个数
//a—单个点的点值(数组) 
//w—区间和(数组)
//lzy—延迟标记(数组) 
//赋值操作 
void pushup(const int u){
	//u为要赋值的结点 
	w[u]=w[u*2]+w[u*2+1];//u*2是父节点u的左子树,u*2+1是其的右子树 
	return;
}
//递归建造线段树 
void build(const int u,int l,int r){
    //u—当前结点,l—其左子结点,r—其右子结点 
	if(l==r){//没有子结点,即点u为叶子结点 
		w[u]=a[l];//赋值 
		return;
	}
	int mid=(l+r)/2;//将区间分为左右子区间
	build(u*2,l,mid);//递归建立其左子树
	build(u*2+1,mid+1,r);//递归建立其右子树
	pushup(u);//由其左右子区间更新该区间的和 
	return;
}
//单点修改操作
void update1(int u,int l,int r,int p,long long x){
    //u—当前结点,l—其左子结点,r—其右子结点 p—要修改的结点 x—要修改的值 
	if(l==r){//到达叶节点直接赋值 
		w[u]=x;
	}else {
		int mid=(l+r)/2;//将区间分为左右子区间
		if(mid>=p){//如果要修改的位置在左子树的区间,修改左子树 
			update1(u*2,l,mid,p,x);
		}else{
			update1(u*2+1,mid+1,r,p,x);//否则修改右子树的区间 
		}
		pushup(u);//更新当前节点的值 
	}
	return;
}
//单点查询操作 
long long query1(int u,int l,int r,int p){
	//u—当前结点,l—其左子结点,r—其右子结点 p—要查询的结点 
	if(l==r){//抵达叶结点就返回 
		return w[u];
	}else {
		int mid=(l+r)/2;//将区间分为左右子区间
		if(mid>=p){
			return query1(u*2,l,mid,p);//如果要查询的位置在左子树的区间,就查询左子树的区间 
		}else{
			return query1(u*2+1,mid+1,r,p);//反之查询右子树的区间 
		}
	}
}
//判断一个子区间是否被另一个完全包含 
bool inrange(int l1,int r1,int l2,int r2){
	//l1—一个子区间的左端点 r1—一个子区间的右端点 l2—另一个子区间的左端点 r2—另一个子区间的右端点
	return(l2<=l1)&&(r1<=r2);//判断[l1,r1]是否被[l2,r2]完全包含 
}
//判断一个子区间是否完全与另一个无交 
bool outofrange(int l1,int r1,int l2,int r2){
	//l1—一个子区间的左端点 r1—一个子区间的右端点 l2—另一个子区间的左端点 r2—另一个子区间的右端点
	return (l1>r2)||(r1<l2);//判断[l1,r1]是否与[l2,r2]完全无交 
}
//区间查询操作 
long long query2(int u,int l1,int r1,int l2,int r2){
	//u—当前结点,l1—其左子结点,r1—其右子结点 l2—要查询的区间的左端点 r2—要查询的区间的右端点 
	if(inrange(l1,r1,l2,r2)){//如果被完全包含就返回该区间区间和
		return w[u];
	}else if(!outofrange(l1,r1,l2,r2)){//如果有区间局部被包含了 
		int mid=(l1+r1)/2;//将区间分为左右子区间
		return query2(u*2,l1,mid,l2,r2)+query2(u*2+1,mid+1,r1,l2,r2);//返回左右子区间中包含目标区间中的元素的值的和 
	}else return 0;//否则一定完全无交 
}
//放置延迟标记 	
void maketag(int u,int len,long long x){
	//u—要放置延迟标记的结点 len—要在u结点的子区间内放置延迟标记的结点个数 x—要放置的延迟标记的值 
	lzy[u]+=x;//修改当前结点的延迟标记 
	w[u]+=len*x;//修改当前结点的区间和 
	return;
}
//把延迟标记放置到下一层 
void pushdown(int u,int l,int r){
	//u—当前结点,l—其左子结点,r—其右子结点
	int mid=(l+r)/2;//将区间分为左右子区间
	maketag(u*2,mid-l+1,lzy[u]);//为u结点的左子树加上延迟标记 
	maketag(u*2+1,r-mid,lzy[u]);//为u结点的右子树加上延迟标记
	lzy[u]=0;//延迟标记以传至下一层,清空当前层的延迟标记
	return;
}
//区间修改 
void update2(int u,int l1,int r1,int l2,int r2,long long x){
	//l1—一个子区间的左端点 r1—一个子区间的右端点 l2—要修改的子区间的左端点 r2—要修改的子区间的右端点 x—要修改的值 
	if(inrange(l1,r1,l2,r2)){//如果完全被包含
		maketag(u,r1-l1+1,x);//直接给该区间打上延迟标记 
	}else if(!outofrange(l1,r1,l2,r2)){
		int mid=(l1+r1)/2;//将区间分为左右子区间
		pushdown(u,l1,r1);//下传延迟标记 
		update2(u*2,l1,mid,l2,r2,x);//递归修改以为u结点的左子树
		update2(u*2+1,mid+1,r1,l2,r2,x);//递归修改以为u结点的右子树
		pushup(u);//修改u
	}
	return;
} 
int main(){	
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);//建立线段树 
	for(int t=1;t<=m;t++){
		int op,x,y;
		long long k=0;
		cin>>op;//表示操作(修改/查询) 
		if(op==1){//如果要修改区间 
			//x—要修改的子区间的左端点 y—要修改的子区间的右端点 k—增加的值 
			cin>>x>>y>>k;
			update2(1,1,n,x,y,k);
		}else {//否则查询区间和
			//x—要查询的区间的左端点 y—要查询的区间的右端点 
			cin>>x>>y;
			cout<<query2(1,1,n,x,y)<<endl;
		}
	}
	return 0;
}
2023/7/17 20:51
加载中...