70分求助
查看原帖
70分求助
1175242
Zxx20120715楼主2024/5/22 18:41
#include<iostream>
using namespace std;
const int maxn=100010;
int n,m,a[maxn];
struct node//线段树的一个节点 
{
	//第一个需要修改的地方:增加维护的值 
	int l,r;//这段区间的左端点、右端点
	int sum;//这段区间的和
	int minv;//这段区间的最小值 
	int tag;//懒标记
	//代表当前节点所对应的区间 每一个数都被加了tag
	//但是 这件事还没有告诉当前节点的两个儿子 
	node(){
		//第二个需要修改的地方:增加维护的值的初始化 
		l=r=sum=tag=minv=0;
	} 
}z[maxn*4];//z[i]代表线段树的第i个节点

#define root 1,n,1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

node operator+(const node &l,const node &r)//定义线段树如何合并两个区间 
{
	//第三个需要修改的地方:增加维护的值 计算方法 
	node res;
	
	res.l=l.l; res.r=r.r;
	res.sum = l.sum + r.sum;
	res.minv = min(l.minv,r.minv);
	
	return res;
}

void build(int l,int r,int rt)//当前的线段树节点编号为rt 其所对应的区间为l~r
//建立这棵线段树 
{
	if (l==r)//走到了最下面 区间只有一个数 那就建立这个节点 
	{
		//第四个需要修改的地方:长度为1的区间这个值怎么处理 
		z[rt].l=z[rt].r=l;
		z[rt].sum = a[l];
		z[rt].minv=a[l];
		return;
	}
	int m=(l+r)>>1;//从l~r中间砍开 l~m作为左儿子区间 m+1~r作为右儿子区间
	build(lson);//build(l,m,rt<<1);//build(l,m,rt*2);//建立左儿子 
	build(rson);//build(m+1,r,rt<<1|1);//build(m+1,r,rt*2+1);//建立右儿子 
	z[rt] = z[rt<<1] + z[rt<<1|1];
} 

void color(int rt,int v)//给节点rt打一个+v的懒标记
{
	//第五个需要修改的地方:增加维护的值的打标记方法 
	z[rt].sum += v * (z[rt].r-z[rt].l+1);
	z[rt].tag += v;
	z[rt].minv += v;
} 

void push_col(int rt)//把节点rt的标记告诉它的儿子
{
	if (z[rt].tag != 0)
	{
		color(rt<<1,z[rt].tag);
		color(rt<<1|1,z[rt].tag);
		z[rt].tag=0;
	}
} 

node query(int l,int r,int rt,int nowl,int nowr)//logn
//当前线段树节点为l~r,编号为rt 此时要询问nowl~nowr这段区间
{
	if (nowl<=l && r<=nowr) return z[rt];//l~r当前线段树节点所对应的区间被询问区间完全包含
	push_col(rt);//把懒标记下放 
	int m=(l+r)>>1; 
	if (nowl<=m)//询问区间和左儿子有交 
	{
		if (m<nowr)//询问区间和右儿子有交
			return query(lson,nowl,nowr) + query(rson,nowl,nowr);
		else//代表只和左儿子有交
			return query(lson,nowl,nowr); 
	}
	else//只和右儿子有交
		return query(rson,nowl,nowr); 
} 

void modify(int l,int r,int rt,int nowl,int nowr,int v)
//当前线段树节点编号为rt 区间为l~r
//修改操作为给nowl~nowr这段区间整体+v
{
	if (nowl<=l && r<=nowr) {//当前区间被修改区间整体包含 
		color(rt,v);//给节点rt打一个整体+v的懒标记
		return; 
	}
	push_col(rt);//把懒标记下放 
	int m=(l+r)>>1;
	if (nowl<=m) modify(lson,nowl,nowr,v);//修改区间和左儿子有交 
	if (m<nowr) modify(rson,nowl,nowr,v);//修改区间和右儿子有交
	z[rt] = z[rt<<1] + z[rt<<1|1]; 
} 

int main()
{
	cin >> n >> m;
	for (int i=1;i<=n;i++)
		cin >> a[i];
		
	build(root);//建树 
	for (int i=1;i<=m;i++)
	{
		int opt;
		cin >> opt;
		if (opt==1)//修改操作
		{
			int x,y,k;
			cin >> x >> y >> k;
			modify(root,x,y,k);
		}
		else//询问操作 
		{
			int x,y;
			cin >> x >> y;
			cout << query(root,x,y).sum << endl;
		} 
	}
	
	return 0;
}

这位蒟蒻在 #8 #9 #10 WA,求助。

2024/5/22 18:41
加载中...